mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 02:15:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1989 lines
		
	
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1989 lines
		
	
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Support for overlapped IO
 | |
|  *
 | |
|  * Some code borrowed from Modules/_winapi.c of CPython
 | |
|  */
 | |
| 
 | |
| /* XXX check overflow and DWORD <-> Py_ssize_t conversions
 | |
|    Check itemsize */
 | |
| 
 | |
| #include "Python.h"
 | |
| #include "structmember.h"         // PyMemberDef
 | |
| 
 | |
| #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
 | |
| 
 | |
| /*[python input]
 | |
| class OVERLAPPED_converter(CConverter):
 | |
|     type = 'OVERLAPPED *'
 | |
|     format_unit = '"F_POINTER"'
 | |
| 
 | |
| class HANDLE_converter(CConverter):
 | |
|     type = 'HANDLE'
 | |
|     format_unit = '"F_HANDLE"'
 | |
| 
 | |
| class ULONG_PTR_converter(CConverter):
 | |
|     type = 'ULONG_PTR'
 | |
|     format_unit = '"F_ULONG_PTR"'
 | |
| 
 | |
| class DWORD_converter(CConverter):
 | |
|     type = 'DWORD'
 | |
|     format_unit = 'k'
 | |
| 
 | |
| class BOOL_converter(CConverter):
 | |
|     type = 'BOOL'
 | |
|     format_unit = 'i'
 | |
| [python start generated code]*/
 | |
| /*[python end generated code: output=da39a3ee5e6b4b0d input=83bb8c2c2514f2a8]*/
 | |
| 
 | |
| /*[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};
 | |
| 
 | |
| 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;
 | |
|     };
 | |
| } OverlappedObject;
 | |
| 
 | |
| typedef struct {
 | |
|     PyTypeObject *overlapped_type;
 | |
| } OverlappedState;
 | |
| 
 | |
| static inline OverlappedState*
 | |
| overlapped_get_state(PyObject *module)
 | |
| {
 | |
|     void *state = PyModule_GetState(module);
 | |
|     assert(state != NULL);
 | |
|     return (OverlappedState *)state;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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;
 | |
| static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
 | |
| 
 | |
| #define GET_WSA_POINTER(s, x)                                           \
 | |
|     (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,    \
 | |
|                               &Guid##x, sizeof(Guid##x), &Py_##x,       \
 | |
|                               sizeof(Py_##x), &dwBytes, NULL, NULL))
 | |
| 
 | |
| static int
 | |
| initialize_function_pointers(void)
 | |
| {
 | |
|     GUID GuidAcceptEx = WSAID_ACCEPTEX;
 | |
|     GUID GuidConnectEx = WSAID_CONNECTEX;
 | |
|     GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
 | |
|     GUID GuidTransmitFile = WSAID_TRANSMITFILE;
 | |
|     HINSTANCE hKernel32;
 | |
|     SOCKET s;
 | |
|     DWORD dwBytes;
 | |
| 
 | |
|     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);
 | |
| 
 | |
|     /* On WinXP we will have Py_CancelIoEx == NULL */
 | |
|     Py_BEGIN_ALLOW_THREADS
 | |
|     hKernel32 = GetModuleHandle("KERNEL32");
 | |
|     *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
 | |
|     Py_END_ALLOW_THREADS
 | |
|     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]*/
 | |
| {
 | |
|     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))
 | |
|     {
 | |
|         PyMem_RawFree(pdata);
 | |
|         return SetFromWindowsErr(0);
 | |
|     }
 | |
| 
 | |
|     return Py_BuildValue(F_HANDLE, NewWaitObject);
 | |
| }
 | |
| 
 | |
| /*[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]*/
 | |
| {
 | |
|     BOOL ret;
 | |
| 
 | |
|     Py_BEGIN_ALLOW_THREADS
 | |
|     ret = UnregisterWait(WaitHandle);
 | |
|     Py_END_ALLOW_THREADS
 | |
| 
 | |
|     if (!ret)
 | |
|         return SetFromWindowsErr(0);
 | |
|     Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| /*[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]*/
 | |
| {
 | |
|     BOOL ret;
 | |
| 
 | |
|     Py_BEGIN_ALLOW_THREADS
 | |
|     ret = UnregisterWaitEx(WaitHandle, Event);
 | |
|     Py_END_ALLOW_THREADS
 | |
| 
 | |
|     if (!ret)
 | |
|         return SetFromWindowsErr(0);
 | |
|     Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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 Py_UNICODE *Name)
 | |
| /*[clinic end generated code: output=8e04f0916c17b13d 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, "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
 | |
|  */
 | |
| 
 | |
| /*[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;
 | |
|         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
 | |
|  */
 | |
| 
 | |
| static 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. */
 | |
| static int
 | |
| 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_WRITE:
 | |
|         case TYPE_WRITE_TO:
 | |
|         case TYPE_READINTO: {
 | |
|             if (self->user_buffer.obj) {
 | |
|                 PyBuffer_Release(&self->user_buffer);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     self->type = TYPE_NOT_STARTED;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| Overlapped_dealloc(OverlappedObject *self)
 | |
| {
 | |
|     DWORD bytes;
 | |
|     DWORD olderr = GetLastError();
 | |
|     BOOL wait = FALSE;
 | |
|     BOOL ret;
 | |
| 
 | |
|     if (!HasOverlappedIoCompleted(&self->overlapped) &&
 | |
|         self->type != TYPE_NOT_STARTED)
 | |
|     {
 | |
|         if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
 | |
|             wait = TRUE;
 | |
| 
 | |
|         Py_BEGIN_ALLOW_THREADS
 | |
|         ret = GetOverlappedResult(self->handle, &self->overlapped,
 | |
|                                   &bytes, wait);
 | |
|         Py_END_ALLOW_THREADS
 | |
| 
 | |
|         switch (ret ? ERROR_SUCCESS : GetLastError()) {
 | |
|             case ERROR_SUCCESS:
 | |
|             case ERROR_NOT_FOUND:
 | |
|             case ERROR_OPERATION_ABORTED:
 | |
|                 break;
 | |
|             default:
 | |
|                 PyErr_Format(
 | |
|                     PyExc_RuntimeError,
 | |
|                     "%R still has pending operation at "
 | |
|                     "deallocation, the process may crash", self);
 | |
|                 PyErr_WriteUnraisable(NULL);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     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
 | |
|         if (Py_CancelIoEx)
 | |
|             ret = Py_CancelIoEx(self->handle, &self->overlapped);
 | |
|         else
 | |
|             ret = CancelIo(self->handle);
 | |
|         Py_END_ALLOW_THREADS
 | |
|     }
 | |
| 
 | |
|     /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
 | |
|     if (!ret && GetLastError() != ERROR_NOT_FOUND)
 | |
|         return 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=aa5b03e9897ca074]*/
 | |
| {
 | |
|     DWORD transferred = 0;
 | |
|     BOOL ret;
 | |
|     DWORD err;
 | |
|     PyObject *addr;
 | |
| 
 | |
|     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;
 | |
|             }
 | |
|             /* fall through */
 | |
|         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;
 | |
| 
 | |
|             Py_INCREF(self->allocated_buffer);
 | |
|             return 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_New(2);
 | |
|             if (self->read_from.result == NULL) {
 | |
|                 Py_CLEAR(addr);
 | |
|                 return NULL;
 | |
|             }
 | |
| 
 | |
|             // first item: message
 | |
|             Py_INCREF(self->read_from.allocated_buffer);
 | |
|             PyTuple_SET_ITEM(self->read_from.result, 0,
 | |
|                              self->read_from.allocated_buffer);
 | |
|             // second item: address
 | |
|             PyTuple_SET_ITEM(self->read_from.result, 1, addr);
 | |
| 
 | |
|             Py_INCREF(self->read_from.result);
 | |
|             return self->read_from.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: object
 | |
|     /
 | |
| 
 | |
| Start overlapped receive.
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
 | |
|                                          HANDLE handle, PyObject *bufobj)
 | |
| /*[clinic end generated code: output=1e9e712e742e5b2a input=16f6cc268d1d0387]*/
 | |
| {
 | |
|     if (self->type != TYPE_NONE) {
 | |
|         PyErr_SetString(PyExc_ValueError, "operation already attempted");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
 | |
|         return NULL;
 | |
| 
 | |
| #if SIZEOF_SIZE_T > SIZEOF_LONG
 | |
|     if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
 | |
|         PyBuffer_Release(&self->user_buffer);
 | |
|         PyErr_SetString(PyExc_ValueError, "buffer too large");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     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: object
 | |
|     flags: DWORD
 | |
|     /
 | |
| 
 | |
| Start overlapped receive.
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
 | |
|                                         HANDLE handle, PyObject *bufobj,
 | |
|                                         DWORD flags)
 | |
| /*[clinic end generated code: output=9a438abc436fe87c input=4f87c38fc381d525]*/
 | |
| {
 | |
|     if (self->type != TYPE_NONE) {
 | |
|         PyErr_SetString(PyExc_ValueError, "operation already attempted");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
 | |
|         return NULL;
 | |
| 
 | |
| #if SIZEOF_SIZE_T > SIZEOF_LONG
 | |
|     if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
 | |
|         PyBuffer_Release(&self->user_buffer);
 | |
|         PyErr_SetString(PyExc_ValueError, "buffer too large");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     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: object
 | |
|     /
 | |
| 
 | |
| Start overlapped write.
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
 | |
|                                       PyObject *bufobj)
 | |
| /*[clinic end generated code: output=c376230b6120d877 input=b8d9a7608d8a1e72]*/
 | |
| {
 | |
|     DWORD written;
 | |
|     BOOL ret;
 | |
|     DWORD err;
 | |
| 
 | |
|     if (self->type != TYPE_NONE) {
 | |
|         PyErr_SetString(PyExc_ValueError, "operation already attempted");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
 | |
|         return NULL;
 | |
| 
 | |
| #if SIZEOF_SIZE_T > SIZEOF_LONG
 | |
|     if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
 | |
|         PyBuffer_Release(&self->user_buffer);
 | |
|         PyErr_SetString(PyExc_ValueError, "buffer too large");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     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: object
 | |
|     flags: DWORD
 | |
|     /
 | |
| 
 | |
| Start overlapped send.
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
 | |
|                                     PyObject *bufobj, DWORD flags)
 | |
| /*[clinic end generated code: output=316031c7467040cc input=932e7cba6d18f708]*/
 | |
| {
 | |
|     DWORD written;
 | |
|     WSABUF wsabuf;
 | |
|     int ret;
 | |
|     DWORD err;
 | |
| 
 | |
|     if (self->type != TYPE_NONE) {
 | |
|         PyErr_SetString(PyExc_ValueError, "operation already attempted");
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
 | |
|         return NULL;
 | |
| 
 | |
| #if SIZEOF_SIZE_T > SIZEOF_LONG
 | |
|     if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
 | |
|         PyBuffer_Release(&self->user_buffer);
 | |
|         PyErr_SetString(PyExc_ValueError, "buffer too large");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     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;
 | |
|     Py_UNICODE *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;
 | |
|         }
 | |
| #if USE_UNICODE_WCHAR_CACHE
 | |
|         Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
 | |
| #else /* USE_UNICODE_WCHAR_CACHE */
 | |
|         Host = PyUnicode_AsWideCharString(Host_obj, NULL);
 | |
| #endif /* USE_UNICODE_WCHAR_CACHE */
 | |
|         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);
 | |
|         }
 | |
| #if !USE_UNICODE_WCHAR_CACHE
 | |
|         PyMem_Free(Host);
 | |
| #endif /* USE_UNICODE_WCHAR_CACHE */
 | |
|         return Length;
 | |
|     }
 | |
|     case 4: {
 | |
|         if (!PyArg_ParseTuple(obj,
 | |
|                 "UHkk;ConnectEx(): illegal address_as_bytes argument",
 | |
|                 &Host_obj, &Port, &FlowInfo, &ScopeId))
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| #if USE_UNICODE_WCHAR_CACHE
 | |
|         Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
 | |
| #else /* USE_UNICODE_WCHAR_CACHE */
 | |
|         Host = PyUnicode_AsWideCharString(Host_obj, NULL);
 | |
| #endif /* USE_UNICODE_WCHAR_CACHE */
 | |
|         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;
 | |
|         }
 | |
| #if !USE_UNICODE_WCHAR_CACHE
 | |
|         PyMem_Free(Host);
 | |
| #endif /* USE_UNICODE_WCHAR_CACHE */
 | |
|         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 Py_UNICODE *Address)
 | |
| /*[clinic end generated code: output=3cc9661667d459d4 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(OverlappedObject *self)
 | |
| {
 | |
|     return PyLong_FromVoidPtr(&self->overlapped);
 | |
| }
 | |
| 
 | |
| static PyObject*
 | |
| Overlapped_getpending(OverlappedObject *self)
 | |
| {
 | |
|     return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
 | |
|                            self->type != TYPE_NOT_STARTED);
 | |
| }
 | |
| 
 | |
| static 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:
 | |
|     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);
 | |
|     }
 | |
|     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
 | |
|     /
 | |
| 
 | |
| 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=169f8075e9ae7fa4]*/
 | |
| {
 | |
|     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: object
 | |
|     flags: DWORD
 | |
|     address_as_bytes as AddressObj: object
 | |
|     /
 | |
| 
 | |
| Start overlapped sendto over a connectionless (UDP) socket.
 | |
| [clinic start generated code]*/
 | |
| 
 | |
| static PyObject *
 | |
| _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
 | |
|                                       PyObject *bufobj, DWORD flags,
 | |
|                                       PyObject *AddressObj)
 | |
| /*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/
 | |
| {
 | |
|     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 (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
| #if SIZEOF_SIZE_T > SIZEOF_LONG
 | |
|     if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
 | |
|         PyBuffer_Release(&self->user_buffer);
 | |
|         PyErr_SetString(PyExc_ValueError, "buffer too large");
 | |
|         return NULL;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     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");
 | |
| 
 | |
| /*[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]*/
 | |
| {
 | |
|     DWORD nread;
 | |
|     PyObject *buf;
 | |
|     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.len = size;
 | |
|     wsabuf.buf = PyBytes_AS_STRING(buf);
 | |
| 
 | |
|     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:
 | |
|         self->type = TYPE_NOT_STARTED;
 | |
|         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_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", 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},
 | |
| };
 | |
| 
 | |
| 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}
 | |
| };
 | |
| 
 | |
| static int
 | |
| overlapped_traverse(PyObject *module, visitproc visit, void *arg)
 | |
| {
 | |
|     OverlappedState *state = overlapped_get_state(module);
 | |
|     Py_VISIT(state->overlapped_type);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| overlapped_clear(PyObject *module)
 | |
| {
 | |
|     OverlappedState *state = overlapped_get_state(module);
 | |
|     Py_CLEAR(state->overlapped_type);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| overlapped_free(void *module)
 | |
| {
 | |
|     overlapped_clear((PyObject *)module);
 | |
| }
 | |
| 
 | |
| #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)
 | |
| {
 | |
|     /* 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;
 | |
|     }
 | |
| 
 | |
|     OverlappedState *st = overlapped_get_state(module);
 | |
|     st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(
 | |
|         module, &overlapped_type_spec, NULL);
 | |
|     if (st->overlapped_type == NULL) {
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     if (PyModule_AddType(module, st->overlapped_type) < 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,  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_mod_exec, overlapped_exec},
 | |
|     {0, NULL}
 | |
| };
 | |
| 
 | |
| static struct PyModuleDef overlapped_module = {
 | |
|     PyModuleDef_HEAD_INIT,
 | |
|     .m_name = "_overlapped",
 | |
|     .m_size = sizeof(OverlappedState),
 | |
|     .m_methods = overlapped_functions,
 | |
|     .m_slots = overlapped_slots,
 | |
|     .m_traverse = overlapped_traverse,
 | |
|     .m_clear = overlapped_clear,
 | |
|     .m_free = overlapped_free
 | |
| };
 | |
| 
 | |
| PyMODINIT_FUNC
 | |
| PyInit__overlapped(void)
 | |
| {
 | |
|     return PyModuleDef_Init(&overlapped_module);
 | |
| }
 | 
