12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069 |
- /*
- * 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 pointer_converter(CConverter):
- format_unit = '"F_POINTER"'
- def parse_arg(self, argname, displayname):
- return """
- {paramname} = PyLong_AsVoidPtr({argname});
- if (!{paramname} && PyErr_Occurred()) {{{{
- goto exit;
- }}}}
- """.format(argname=argname, paramname=self.parser_name)
- class OVERLAPPED_converter(pointer_converter):
- type = 'OVERLAPPED *'
- class HANDLE_converter(pointer_converter):
- type = 'HANDLE'
- class ULONG_PTR_converter(pointer_converter):
- type = 'ULONG_PTR'
- def parse_arg(self, argname, displayname):
- return """
- {paramname} = (uintptr_t)PyLong_AsVoidPtr({argname});
- if (!{paramname} && PyErr_Occurred()) {{{{
- goto exit;
- }}}}
- """.format(argname=argname, paramname=self.parser_name)
- class DWORD_converter(unsigned_long_converter):
- type = 'DWORD'
- class BOOL_converter(int_converter):
- type = 'BOOL'
- [python start generated code]*/
- /*[python end generated code: output=da39a3ee5e6b4b0d input=8a07ea3018f4cec8]*/
- /*[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;
- 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]*/
- {
- 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);
- }
- /*[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 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. */
- 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_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;
- 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)
- {
- 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_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
- 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=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;
- }
- else if (self->type == TYPE_READ_FROM_INTO &&
- self->read_from_into.result != 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;
- 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_New(2);
- if (self->read_from.result == NULL) {
- Py_CLEAR(addr);
- return NULL;
- }
- // first item: message
- PyTuple_SET_ITEM(self->read_from.result, 0,
- Py_NewRef(self->read_from.allocated_buffer));
- // second item: address
- PyTuple_SET_ITEM(self->read_from.result, 1, addr);
- 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;
- }
- // The result is a two item tuple: (number of bytes read, address)
- self->read_from_into.result = PyTuple_New(2);
- if (self->read_from_into.result == NULL) {
- Py_CLEAR(addr);
- return NULL;
- }
- // first item: number of bytes read
- PyTuple_SET_ITEM(self->read_from_into.result, 0,
- PyLong_FromUnsignedLong((unsigned long)transferred));
- // second item: address
- PyTuple_SET_ITEM(self->read_from_into.result, 1, addr);
- 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 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);
- 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:
- 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]*/
- {
- 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:
- self->type = TYPE_NOT_STARTED;
- 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
- 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:
- 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_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", 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}
- };
- #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;
- }
- 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, 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},
- {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
- {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);
- }
|