123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088 |
- /*
- * 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)
- {
- // NOTE: We should not get here, if we do then something is wrong in
- // the IocpProactor or ProactorEventLoop. Since everything uses IOCP if
- // the overlapped IO hasn't completed yet then we should not be
- // deallocating!
- //
- // The problem is likely that this OverlappedObject was removed from
- // the IocpProactor._cache before it was complete. The _cache holds a
- // reference while IO is pending so that it does not get deallocated
- // while the kernel has retained the OVERLAPPED structure.
- //
- // CancelIoEx (likely called from self.cancel()) may have successfully
- // completed, but the OVERLAPPED is still in use until either
- // HasOverlappedIoCompleted() is true or GetQueuedCompletionStatus has
- // returned this OVERLAPPED object.
- //
- // NOTE: Waiting when IOCP is in use can hang indefinitely, but this
- // CancelIoEx is superfluous in that self.cancel() was already called,
- // so I've only ever seen this return FALSE with GLE=ERROR_NOT_FOUND
- Py_BEGIN_ALLOW_THREADS
- if (CancelIoEx(self->handle, &self->overlapped))
- wait = TRUE;
- ret = GetOverlappedResult(self->handle, &self->overlapped,
- &bytes, wait);
- Py_END_ALLOW_THREADS
- switch (ret ? ERROR_SUCCESS : GetLastError()) {
- case ERROR_SUCCESS:
- case ERROR_NOT_FOUND:
- case ERROR_OPERATION_ABORTED:
- break;
- default:
- PyErr_Format(
- PyExc_RuntimeError,
- "%R still has pending operation at "
- "deallocation, the process may crash", self);
- PyErr_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, ERROR_PORT_UNREACHABLE);
- WINAPI_CONSTANT(F_DWORD, INFINITE);
- WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
- WINAPI_CONSTANT(F_HANDLE, NULL);
- WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
- WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
- WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
- return 0;
- }
- static PyModuleDef_Slot overlapped_slots[] = {
- {Py_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);
- }
|