| /* | |
| * Support for overlapped IO | |
| * | |
| * Some code borrowed from Modules/_winapi.c of CPython | |
| */ | |
| /* XXX check overflow and DWORD <-> Py_ssize_t conversions | |
| Check itemsize */ | |
| #ifndef Py_BUILD_CORE_BUILTIN | |
| # define Py_BUILD_CORE_MODULE 1 | |
| #endif | |
| #include "Python.h" | |
| #include "pycore_tuple.h" // _PyTuple_FromPairSteal | |
| #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 Py_T_ULONG | |
| #else | |
| # define F_POINTER "K" | |
| # define T_POINTER Py_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 | |
| #ifndef HasOverlappedIoCompleted | |
| #define HasOverlappedIoCompleted(lpOverlapped) (lpOverlapped)->Internal != STATUS_PENDING | |
| #endif | |
| /*[python input] | |
| class pointer_converter(CConverter): | |
| format_unit = '"F_POINTER"' | |
| def parse_arg(self, argname, displayname, *, limited_capi): | |
| return self.format_code(""" | |
| {paramname} = PyLong_AsVoidPtr({argname}); | |
| if (!{paramname} && PyErr_Occurred()) {{{{ | |
| goto exit; | |
| }}}} | |
| """, | |
| argname=argname) | |
| class OVERLAPPED_converter(pointer_converter): | |
| type = 'OVERLAPPED *' | |
| class ULONG_PTR_converter(pointer_converter): | |
| type = 'ULONG_PTR' | |
| def parse_arg(self, argname, displayname, *, limited_capi): | |
| return self.format_code(""" | |
| {paramname} = (uintptr_t)PyLong_AsVoidPtr({argname}); | |
| if (!{paramname} && PyErr_Occurred()) {{{{ | |
| goto exit; | |
| }}}} | |
| """, | |
| argname=argname) | |
| [python start generated code]*/ | |
| /*[python end generated code: output=da39a3ee5e6b4b0d input=e3b1c126cba99725]*/ | |
| /*[clinic input] | |
| module _overlapped | |
| class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType" | |
| [clinic start generated code]*/ | |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=92e5a799db35b96c]*/ | |
| enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE, | |
| TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE, | |
| TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM, | |
| TYPE_WRITE_TO, TYPE_READ_FROM_INTO}; | |
| 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 { | |
| /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */ | |
| PyObject *allocated_buffer; | |
| /* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */ | |
| Py_buffer user_buffer; | |
| /* 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; | |
| /* 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 */ | |
| Py_buffer user_buffer; | |
| struct sockaddr_in6 address; | |
| int address_length; | |
| } read_from_into; | |
| }; | |
| } OverlappedObject; | |
| #define OverlappedObject_CAST(op) ((OverlappedObject *)(op)) | |
| static inline void | |
| steal_buffer(Py_buffer * dst, Py_buffer * src) | |
| { | |
| memcpy(dst, src, sizeof(Py_buffer)); | |
| memset(src, 0, sizeof(Py_buffer)); | |
| } | |
| /* | |
| * 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; | |
| static LPFN_TRANSMITFILE Py_TransmitFile = 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; | |
| GUID GuidTransmitFile = WSAID_TRANSMITFILE; | |
| SOCKET s; | |
| DWORD dwBytes; | |
| 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; | |
| } | |
| 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) || | |
| !GET_WSA_POINTER(s, DisconnectEx) || | |
| !GET_WSA_POINTER(s, TransmitFile)) | |
| { | |
| closesocket(s); | |
| SetFromWindowsErr(WSAGetLastError()); | |
| return -1; | |
| } | |
| closesocket(s); | |
| return 0; | |
| } | |
| /* | |
| * Completion port stuff | |
| */ | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle, | |
| HANDLE ExistingCompletionPort, | |
| ULONG_PTR CompletionKey, | |
| DWORD NumberOfConcurrentThreads) | |
| /*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/ | |
| { | |
| 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); | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_GetQueuedCompletionStatus_impl(PyObject *module, | |
| HANDLE CompletionPort, | |
| DWORD Milliseconds) | |
| /*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/ | |
| { | |
| 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); | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_PostQueuedCompletionStatus_impl(PyObject *module, | |
| HANDLE CompletionPort, | |
| DWORD NumberOfBytes, | |
| ULONG_PTR CompletionKey, | |
| OVERLAPPED *Overlapped) | |
| /*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/ | |
| { | |
| BOOL ret; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes, | |
| CompletionKey, Overlapped); | |
| Py_END_ALLOW_THREADS | |
| if (!ret) | |
| return SetFromWindowsErr(0); | |
| Py_RETURN_NONE; | |
| } | |
| /* | |
| * Wait for a handle | |
| */ | |
| struct PostCallbackData { | |
| HANDLE CompletionPort; | |
| LPOVERLAPPED Overlapped; | |
| }; | |
| static VOID CALLBACK | |
| PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) | |
| { | |
| struct PostCallbackData *p = (struct PostCallbackData*) lpParameter; | |
| PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired, | |
| 0, p->Overlapped); | |
| /* ignore possible error! */ | |
| PyMem_RawFree(p); | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object, | |
| HANDLE CompletionPort, | |
| OVERLAPPED *Overlapped, | |
| DWORD Milliseconds) | |
| /*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/ | |
| { | |
| #ifndef MS_WINDOWS_DESKTOP | |
| return NULL; | |
| #else | |
| HANDLE NewWaitObject; | |
| struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata; | |
| /* 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)); | |
| if (pdata == NULL) | |
| return SetFromWindowsErr(0); | |
| *pdata = data; | |
| if (!RegisterWaitForSingleObject( | |
| &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds, | |
| WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) | |
| { | |
| SetFromWindowsErr(0); | |
| PyMem_RawFree(pdata); | |
| return NULL; | |
| } | |
| return Py_BuildValue(F_HANDLE, NewWaitObject); | |
| #endif | |
| } | |
| /*[clinic input] | |
| _overlapped.UnregisterWait | |
| WaitHandle: HANDLE | |
| / | |
| Unregister wait handle. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle) | |
| /*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/ | |
| { | |
| #ifndef MS_WINDOWS_DESKTOP | |
| Py_RETURN_NONE; | |
| #else | |
| BOOL ret; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = UnregisterWait(WaitHandle); | |
| Py_END_ALLOW_THREADS | |
| if (!ret) | |
| return SetFromWindowsErr(0); | |
| Py_RETURN_NONE; | |
| #endif | |
| } | |
| /*[clinic input] | |
| _overlapped.UnregisterWaitEx | |
| WaitHandle: HANDLE | |
| Event: HANDLE | |
| / | |
| Unregister wait handle. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle, | |
| HANDLE Event) | |
| /*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/ | |
| { | |
| #ifndef MS_WINDOWS_DESKTOP | |
| Py_RETURN_NONE; | |
| #else | |
| BOOL ret; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = UnregisterWaitEx(WaitHandle, Event); | |
| Py_END_ALLOW_THREADS | |
| if (!ret) | |
| return SetFromWindowsErr(0); | |
| Py_RETURN_NONE; | |
| #endif | |
| } | |
| /* | |
| * Event functions -- currently only used by tests | |
| */ | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes, | |
| BOOL ManualReset, BOOL InitialState, | |
| const wchar_t *Name) | |
| /*[clinic end generated code: output=b17ddc5fd506972d input=dbc36ae14375ba24]*/ | |
| { | |
| 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); | |
| } | |
| /*[clinic input] | |
| _overlapped.SetEvent | |
| Handle: HANDLE | |
| / | |
| Set event. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_SetEvent_impl(PyObject *module, HANDLE Handle) | |
| /*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/ | |
| { | |
| BOOL ret; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = SetEvent(Handle); | |
| Py_END_ALLOW_THREADS | |
| if (!ret) | |
| return SetFromWindowsErr(0); | |
| Py_RETURN_NONE; | |
| } | |
| /*[clinic input] | |
| _overlapped.ResetEvent | |
| Handle: HANDLE | |
| / | |
| Reset event. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle) | |
| /*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/ | |
| { | |
| BOOL ret; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = ResetEvent(Handle); | |
| Py_END_ALLOW_THREADS | |
| if (!ret) | |
| return SetFromWindowsErr(0); | |
| Py_RETURN_NONE; | |
| } | |
| /* | |
| * Bind socket handle to local port without doing slow getaddrinfo() | |
| */ | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family) | |
| /*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/ | |
| { | |
| 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; | |
| ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr)) | |
| != SOCKET_ERROR; | |
| } 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; | |
| ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr)) | |
| != SOCKET_ERROR; | |
| } else { | |
| PyErr_SetString(PyExc_ValueError, "Only AF_INET and AF_INET6 families are supported"); | |
| return NULL; | |
| } | |
| if (!ret) | |
| return SetFromWindowsErr(WSAGetLastError()); | |
| Py_RETURN_NONE; | |
| } | |
| /* | |
| * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c | |
| */ | |
| /*[clinic input] | |
| _overlapped.FormatMessage | |
| error_code as code: DWORD | |
| / | |
| Return error message for an error code. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_FormatMessage_impl(PyObject *module, DWORD code) | |
| /*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/ | |
| { | |
| DWORD n; | |
| WCHAR *lpMsgBuf; | |
| PyObject *res; | |
| n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
| FORMAT_MESSAGE_FROM_SYSTEM | | |
| FORMAT_MESSAGE_IGNORE_INSERTS, | |
| NULL, | |
| code, | |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| (LPWSTR) &lpMsgBuf, | |
| 0, | |
| NULL); | |
| if (n) { | |
| while (iswspace(lpMsgBuf[n-1])) | |
| --n; | |
| res = PyUnicode_FromWideChar(lpMsgBuf, n); | |
| } else { | |
| res = PyUnicode_FromFormat("unknown error code %u", code); | |
| } | |
| LocalFree(lpMsgBuf); | |
| return res; | |
| } | |
| /* | |
| * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE | |
| */ | |
| static inline void | |
| 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 | |
| */ | |
| /*[clinic input] | |
| @classmethod | |
| _overlapped.Overlapped.__new__ | |
| event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE | |
| OVERLAPPED structure wrapper. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event) | |
| /*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/ | |
| { | |
| 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; | |
| self->allocated_buffer = NULL; | |
| memset(&self->overlapped, 0, sizeof(OVERLAPPED)); | |
| memset(&self->user_buffer, 0, sizeof(Py_buffer)); | |
| if (event) | |
| self->overlapped.hEvent = event; | |
| return (PyObject *)self; | |
| } | |
| /* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release | |
| * buffers while overlapped are still running, to prevent a crash. | |
| * | |
| * Note (gh-111178): Since OverlappedType.tp_clear is not used, we do not | |
| * need to prevent an undefined behaviour by changing the type of 'self'. | |
| * To avoid suppressing unused return values, we however make this function | |
| * return nothing instead of 0, as we never use it. | |
| */ | |
| static void | |
| Overlapped_clear(OverlappedObject *self) | |
| { | |
| switch (self->type) { | |
| 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; | |
| } | |
| 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); | |
| } | |
| if (self->read_from_into.user_buffer.obj) { | |
| PyBuffer_Release(&self->read_from_into.user_buffer); | |
| } | |
| break; | |
| } | |
| case TYPE_WRITE: | |
| case TYPE_WRITE_TO: | |
| case TYPE_READINTO: { | |
| if (self->user_buffer.obj) { | |
| PyBuffer_Release(&self->user_buffer); | |
| } | |
| break; | |
| } | |
| } | |
| self->type = TYPE_NOT_STARTED; | |
| } | |
| static void | |
| Overlapped_dealloc(PyObject *op) | |
| { | |
| DWORD bytes; | |
| DWORD olderr = GetLastError(); | |
| BOOL wait = FALSE; | |
| BOOL ret; | |
| OverlappedObject *self = OverlappedObject_CAST(op); | |
| if (!HasOverlappedIoCompleted(&self->overlapped) && | |
| self->type != TYPE_NOT_STARTED) | |
| { | |
| // NOTE: We should not get here, if we do then something is wrong in | |
| // the IocpProactor or ProactorEventLoop. Since everything uses IOCP if | |
| // the overlapped IO hasn't completed yet then we should not be | |
| // deallocating! | |
| // | |
| // The problem is likely that this OverlappedObject was removed from | |
| // the IocpProactor._cache before it was complete. The _cache holds a | |
| // reference while IO is pending so that it does not get deallocated | |
| // while the kernel has retained the OVERLAPPED structure. | |
| // | |
| // CancelIoEx (likely called from self.cancel()) may have successfully | |
| // completed, but the OVERLAPPED is still in use until either | |
| // HasOverlappedIoCompleted() is true or GetQueuedCompletionStatus has | |
| // returned this OVERLAPPED object. | |
| // | |
| // NOTE: Waiting when IOCP is in use can hang indefinitely, but this | |
| // CancelIoEx is superfluous in that self.cancel() was already called, | |
| // so I've only ever seen this return FALSE with GLE=ERROR_NOT_FOUND | |
| Py_BEGIN_ALLOW_THREADS | |
| if (CancelIoEx(self->handle, &self->overlapped)) | |
| 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_FormatUnraisable("Exception ignored while deallocating " | |
| "overlapped operation %R", self); | |
| } | |
| } | |
| if (self->overlapped.hEvent != NULL) { | |
| CloseHandle(self->overlapped.hEvent); | |
| } | |
| Overlapped_clear(self); | |
| SetLastError(olderr); | |
| PyTypeObject *tp = Py_TYPE(self); | |
| PyObject_Free(self); | |
| Py_DECREF(tp); | |
| } | |
| /* 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: { | |
| PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family"); | |
| return NULL; | |
| } | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.cancel | |
| Cancel overlapped operation. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_cancel_impl(OverlappedObject *self) | |
| /*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/ | |
| { | |
| 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 | |
| ret = CancelIoEx(self->handle, &self->overlapped); | |
| 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; | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait) | |
| /*[clinic end generated code: output=8c9bd04d08994f6c input=852fbd817cbd2b3d]*/ | |
| { | |
| DWORD transferred = 0; | |
| BOOL ret; | |
| DWORD err; | |
| PyObject *addr; | |
| PyObject *transferred_obj; | |
| 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->type == TYPE_READ || self->type == TYPE_READINTO) { | |
| break; | |
| } | |
| else if (self->type == TYPE_READ_FROM && | |
| (self->read_from.result != NULL || | |
| self->read_from.allocated_buffer != NULL)) | |
| { | |
| break; | |
| } | |
| else if (self->type == TYPE_READ_FROM_INTO && | |
| self->read_from_into.result != NULL) | |
| { | |
| break; | |
| } | |
| _Py_FALLTHROUGH; | |
| default: | |
| return SetFromWindowsErr(err); | |
| } | |
| switch (self->type) { | |
| case TYPE_READ: | |
| assert(PyBytes_CheckExact(self->allocated_buffer)); | |
| if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) && | |
| _PyBytes_Resize(&self->allocated_buffer, transferred)) | |
| return NULL; | |
| return Py_NewRef(self->allocated_buffer); | |
| 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_FromPairSteal( | |
| Py_NewRef(self->read_from.allocated_buffer), addr); | |
| if (self->read_from.result == NULL) { | |
| return NULL; | |
| } | |
| return Py_NewRef(self->read_from.result); | |
| 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; | |
| } | |
| transferred_obj = PyLong_FromUnsignedLong((unsigned long)transferred); | |
| if (transferred_obj == NULL) { | |
| Py_DECREF(addr); | |
| return NULL; | |
| } | |
| // The result is a two item tuple: (number of bytes read, address) | |
| self->read_from_into.result = _PyTuple_FromPairSteal( | |
| transferred_obj, addr); | |
| if (self->read_from_into.result == NULL) { | |
| return NULL; | |
| } | |
| return Py_NewRef(self->read_from_into.result); | |
| default: | |
| return PyLong_FromUnsignedLong((unsigned long) transferred); | |
| } | |
| } | |
| 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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.ReadFile | |
| handle: HANDLE | |
| size: DWORD | |
| / | |
| Start overlapped read. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle, | |
| DWORD size) | |
| /*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/ | |
| { | |
| 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; | |
| self->allocated_buffer = buf; | |
| return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size); | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.ReadFileInto | |
| handle: HANDLE | |
| buf as bufobj: Py_buffer | |
| / | |
| Start overlapped receive. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self, | |
| HANDLE handle, Py_buffer *bufobj) | |
| /*[clinic end generated code: output=8754744506023071 input=4f037ba09939e32d]*/ | |
| { | |
| 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 | |
| steal_buffer(&self->user_buffer, bufobj); | |
| 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; | |
| wsabuf.buf = bufstart; | |
| wsabuf.len = buflen; | |
| 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_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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WSARecv | |
| handle: HANDLE | |
| size: DWORD | |
| flags: DWORD = 0 | |
| / | |
| Start overlapped receive. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle, | |
| DWORD size, DWORD flags) | |
| /*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/ | |
| { | |
| 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; | |
| self->allocated_buffer = buf; | |
| return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags); | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WSARecvInto | |
| handle: HANDLE | |
| buf as bufobj: Py_buffer | |
| flags: DWORD | |
| / | |
| Start overlapped receive. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self, | |
| HANDLE handle, Py_buffer *bufobj, | |
| DWORD flags) | |
| /*[clinic end generated code: output=59ae7688786cf86b input=73e7fa00db633edd]*/ | |
| { | |
| 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 | |
| steal_buffer(&self->user_buffer, bufobj); | |
| self->type = TYPE_READINTO; | |
| self->handle = handle; | |
| return do_WSARecv(self, handle, self->user_buffer.buf, | |
| (DWORD)self->user_buffer.len, flags); | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WriteFile | |
| handle: HANDLE | |
| buf as bufobj: Py_buffer | |
| / | |
| Start overlapped write. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle, | |
| Py_buffer *bufobj) | |
| /*[clinic end generated code: output=fa5d5880a1bf04b1 input=ac54424c362abfc1]*/ | |
| { | |
| 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 | |
| if (bufobj->len > (Py_ssize_t)ULONG_MAX) { | |
| PyErr_SetString(PyExc_ValueError, "buffer too large"); | |
| return NULL; | |
| } | |
| #endif | |
| steal_buffer(&self->user_buffer, bufobj); | |
| self->type = TYPE_WRITE; | |
| self->handle = handle; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = WriteFile(handle, self->user_buffer.buf, | |
| (DWORD)self->user_buffer.len, | |
| &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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WSASend | |
| handle: HANDLE | |
| buf as bufobj: Py_buffer | |
| flags: DWORD | |
| / | |
| Start overlapped send. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle, | |
| Py_buffer *bufobj, DWORD flags) | |
| /*[clinic end generated code: output=3baaa6e1f7fe229e input=c4167420ba2f93d8]*/ | |
| { | |
| 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 | |
| if (bufobj->len > (Py_ssize_t)ULONG_MAX) { | |
| PyErr_SetString(PyExc_ValueError, "buffer too large"); | |
| return NULL; | |
| } | |
| #endif | |
| steal_buffer(&self->user_buffer, bufobj); | |
| self->type = TYPE_WRITE; | |
| self->handle = handle; | |
| wsabuf.len = (DWORD)self->user_buffer.len; | |
| wsabuf.buf = self->user_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_IO_PENDING: | |
| Py_RETURN_NONE; | |
| default: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self, | |
| HANDLE ListenSocket, | |
| HANDLE AcceptSocket) | |
| /*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/ | |
| { | |
| 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; | |
| self->handle = ListenSocket; | |
| self->allocated_buffer = buf; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| static int | |
| parse_address(PyObject *obj, SOCKADDR *Address, int Length) | |
| { | |
| PyObject *Host_obj; | |
| wchar_t *Host; | |
| unsigned short Port; | |
| unsigned long FlowInfo; | |
| unsigned long ScopeId; | |
| memset(Address, 0, Length); | |
| 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; | |
| } | |
| Address->sa_family = AF_INET; | |
| if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) { | |
| SetFromWindowsErr(WSAGetLastError()); | |
| Length = -1; | |
| } | |
| else { | |
| ((SOCKADDR_IN*)Address)->sin_port = htons(Port); | |
| } | |
| PyMem_Free(Host); | |
| return Length; | |
| } | |
| 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; | |
| } | |
| Address->sa_family = AF_INET6; | |
| if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) { | |
| SetFromWindowsErr(WSAGetLastError()); | |
| Length = -1; | |
| } | |
| else { | |
| ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port); | |
| ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo; | |
| ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId; | |
| } | |
| PyMem_Free(Host); | |
| return Length; | |
| } | |
| default: | |
| PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument"); | |
| return -1; | |
| } | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self, | |
| HANDLE ConnectSocket, | |
| PyObject *AddressObj) | |
| /*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/ | |
| { | |
| 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; | |
| self->handle = ConnectSocket; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = Py_ConnectEx((SOCKET)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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.DisconnectEx | |
| handle as Socket: HANDLE | |
| flags: DWORD | |
| / | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self, | |
| HANDLE Socket, DWORD flags) | |
| /*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/ | |
| { | |
| BOOL ret; | |
| DWORD err; | |
| if (self->type != TYPE_NONE) { | |
| PyErr_SetString(PyExc_ValueError, "operation already attempted"); | |
| return NULL; | |
| } | |
| self->type = TYPE_DISCONNECT; | |
| self->handle = Socket; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = Py_DisconnectEx((SOCKET)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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[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]*/ | |
| static PyObject * | |
| _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]*/ | |
| { | |
| BOOL ret; | |
| DWORD err; | |
| if (self->type != TYPE_NONE) { | |
| PyErr_SetString(PyExc_ValueError, "operation already attempted"); | |
| return NULL; | |
| } | |
| self->type = TYPE_TRANSMIT_FILE; | |
| self->handle = Socket; | |
| self->overlapped.Offset = offset; | |
| self->overlapped.OffsetHigh = offset_high; | |
| Py_BEGIN_ALLOW_THREADS | |
| ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write, | |
| count_per_send, &self->overlapped, NULL, flags); | |
| Py_END_ALLOW_THREADS | |
| self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError(); | |
| switch (err) { | |
| case ERROR_SUCCESS: | |
| case ERROR_IO_PENDING: | |
| Py_RETURN_NONE; | |
| default: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.ConnectNamedPipe | |
| handle as Pipe: HANDLE | |
| / | |
| Start overlapped wait for a client to connect. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self, | |
| HANDLE Pipe) | |
| /*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/ | |
| { | |
| 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); | |
| Py_RETURN_TRUE; | |
| case ERROR_SUCCESS: | |
| case ERROR_IO_PENDING: | |
| Py_RETURN_FALSE; | |
| default: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.ConnectPipe | |
| addr as Address: Py_UNICODE | |
| / | |
| Connect to the pipe for asynchronous I/O (overlapped). | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self, | |
| const wchar_t *Address) | |
| /*[clinic end generated code: output=67cbd8e4d3a57855 input=167c06a274efcefc]*/ | |
| { | |
| HANDLE PipeHandle; | |
| Py_BEGIN_ALLOW_THREADS | |
| PipeHandle = CreateFileW(Address, | |
| GENERIC_READ | GENERIC_WRITE, | |
| 0, NULL, OPEN_EXISTING, | |
| FILE_FLAG_OVERLAPPED, NULL); | |
| Py_END_ALLOW_THREADS | |
| if (PipeHandle == INVALID_HANDLE_VALUE) | |
| return SetFromWindowsErr(0); | |
| return Py_BuildValue(F_HANDLE, PipeHandle); | |
| } | |
| static PyObject* | |
| Overlapped_getaddress(PyObject *op, void *Py_UNUSED(closure)) | |
| { | |
| OverlappedObject *self = OverlappedObject_CAST(op); | |
| return PyLong_FromVoidPtr(&self->overlapped); | |
| } | |
| static PyObject* | |
| Overlapped_getpending(PyObject *op, void *Py_UNUSED(closure)) | |
| { | |
| OverlappedObject *self = OverlappedObject_CAST(op); | |
| return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) && | |
| self->type != TYPE_NOT_STARTED); | |
| } | |
| static int | |
| Overlapped_traverse(PyObject *op, visitproc visit, void *arg) | |
| { | |
| OverlappedObject *self = OverlappedObject_CAST(op); | |
| switch (self->type) { | |
| case TYPE_READ: | |
| case TYPE_ACCEPT: | |
| Py_VISIT(self->allocated_buffer); | |
| break; | |
| case TYPE_WRITE: | |
| case TYPE_WRITE_TO: | |
| case TYPE_READINTO: | |
| if (self->user_buffer.obj) { | |
| Py_VISIT(&self->user_buffer.obj); | |
| } | |
| break; | |
| case TYPE_READ_FROM: | |
| Py_VISIT(self->read_from.result); | |
| Py_VISIT(self->read_from.allocated_buffer); | |
| break; | |
| case TYPE_READ_FROM_INTO: | |
| Py_VISIT(self->read_from_into.result); | |
| if (self->read_from_into.user_buffer.obj) { | |
| Py_VISIT(&self->read_from_into.user_buffer.obj); | |
| } | |
| break; | |
| } | |
| return 0; | |
| } | |
| // UDP functions | |
| /* | |
| * Note: WSAConnect does not support Overlapped I/O so this function should | |
| * _only_ be used for connectionless sockets (UDP). | |
| */ | |
| /*[clinic input] | |
| _overlapped.WSAConnect | |
| client_handle as ConnectSocket: HANDLE | |
| address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') | |
| / | |
| Bind a remote address to a connectionless (UDP) socket. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket, | |
| PyObject *AddressObj) | |
| /*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/ | |
| { | |
| 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. | |
| err = WSAConnect((SOCKET)ConnectSocket, Address, Length, | |
| NULL, NULL, NULL, NULL); | |
| Py_END_ALLOW_THREADS | |
| if (err == 0) { | |
| Py_RETURN_NONE; | |
| } | |
| else { | |
| return SetFromWindowsErr(WSAGetLastError()); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WSASendTo | |
| handle: HANDLE | |
| buf as bufobj: Py_buffer | |
| flags: DWORD | |
| address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type') | |
| / | |
| Start overlapped sendto over a connectionless (UDP) socket. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle, | |
| Py_buffer *bufobj, DWORD flags, | |
| PyObject *AddressObj) | |
| /*[clinic end generated code: output=3cdedc4cfaeb70cd input=31f44cd4ab92fc33]*/ | |
| { | |
| 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 | |
| if (bufobj->len > (Py_ssize_t)ULONG_MAX) { | |
| PyErr_SetString(PyExc_ValueError, "buffer too large"); | |
| return NULL; | |
| } | |
| #endif | |
| steal_buffer(&self->user_buffer, bufobj); | |
| 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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[clinic input] | |
| _overlapped.Overlapped.WSARecvFrom | |
| handle: HANDLE | |
| size: DWORD | |
| flags: DWORD = 0 | |
| / | |
| Start overlapped receive. | |
| [clinic start generated code]*/ | |
| static PyObject * | |
| _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self, | |
| HANDLE handle, DWORD size, | |
| DWORD flags) | |
| /*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/ | |
| { | |
| PyObject *buf; | |
| 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 | |
| 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); | |
| wsabuf.len = size; | |
| 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); | |
| 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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| /*[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 | |
| if (bufobj->len < (Py_ssize_t)size) { | |
| PyErr_SetString(PyExc_ValueError, "nbytes is greater than the length of the buffer"); | |
| return NULL; | |
| } | |
| wsabuf.buf = bufobj->buf; | |
| wsabuf.len = size; | |
| self->type = TYPE_READ_FROM_INTO; | |
| self->handle = handle; | |
| steal_buffer(&self->read_from_into.user_buffer, bufobj); | |
| 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) { | |
| 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: | |
| Overlapped_clear(self); | |
| return SetFromWindowsErr(err); | |
| } | |
| } | |
| #include "clinic/overlapped.c.h" | |
| static PyMethodDef Overlapped_methods[] = { | |
| _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF | |
| _OVERLAPPED_OVERLAPPED_WSARECVFROMINTO_METHODDEF | |
| _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 | |
| {NULL} | |
| }; | |
| static PyMemberDef Overlapped_members[] = { | |
| {"error", Py_T_ULONG, | |
| offsetof(OverlappedObject, error), | |
| Py_READONLY, "Error from last operation"}, | |
| {"event", T_HANDLE, | |
| offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent), | |
| Py_READONLY, "Overlapped event handle"}, | |
| {NULL} | |
| }; | |
| static PyGetSetDef Overlapped_getsets[] = { | |
| {"address", Overlapped_getaddress, NULL, | |
| "Address of overlapped structure"}, | |
| {"pending", Overlapped_getpending, NULL, | |
| "Whether the operation is pending"}, | |
| {NULL}, | |
| }; | |
| 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), | |
| .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), | |
| .slots = overlapped_type_slots | |
| }; | |
| static PyMethodDef overlapped_functions[] = { | |
| _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 | |
| {NULL} | |
| }; | |
| #define WINAPI_CONSTANT(fmt, con) \ | |
| do { \ | |
| if (PyModule_Add(module, #con, Py_BuildValue(fmt, con)) < 0 ) { \ | |
| return -1; \ | |
| } \ | |
| } while (0) | |
| static int | |
| overlapped_exec(PyObject *module) | |
| { | |
| /* Ensure WSAStartup() called before initializing function pointers */ | |
| PyObject *socket_module = PyImport_ImportModule("_socket"); | |
| if (!socket_module) { | |
| return -1; | |
| } | |
| Py_DECREF(socket_module); | |
| if (initialize_function_pointers() < 0) { | |
| return -1; | |
| } | |
| PyTypeObject *overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec( | |
| module, &overlapped_type_spec, NULL); | |
| if (overlapped_type == NULL) { | |
| return -1; | |
| } | |
| int rc = PyModule_AddType(module, overlapped_type); | |
| Py_DECREF(overlapped_type); | |
| if (rc < 0) { | |
| return -1; | |
| } | |
| WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); | |
| WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); | |
| WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); | |
| WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); | |
| WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); | |
| WINAPI_CONSTANT(F_DWORD, ERROR_PORT_UNREACHABLE); | |
| 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 0; | |
| } | |
| static PyModuleDef_Slot overlapped_slots[] = { | |
| _Py_ABI_SLOT, | |
| {Py_mod_exec, overlapped_exec}, | |
| {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, | |
| {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | |
| {0, NULL} | |
| }; | |
| static struct PyModuleDef overlapped_module = { | |
| .m_base = PyModuleDef_HEAD_INIT, | |
| .m_name = "_overlapped", | |
| .m_methods = overlapped_functions, | |
| .m_slots = overlapped_slots, | |
| }; | |
| PyMODINIT_FUNC | |
| PyInit__overlapped(void) | |
| { | |
| return PyModuleDef_Init(&overlapped_module); | |
| } |