def close(self): """Close file. """ if self._handle: try: flags = win32pipe.GetNamedPipeInfo(self._handle)[0] except: flags = 0 if flags & win32con.PIPE_SERVER_END: win32pipe.DisconnectNamedPipe(self._handle) # TODO: if pipe, need to call FlushFileBuffers? def _close_(self, rc, n): win32file.CloseHandle(self._handle) self._overlap = None _AsyncFile._notifier.unregister(self._handle) self._handle = None self._read_result = self._write_result = None self._read_coro = self._write_coro = None self._buflist = [] if self._overlap.object: self._overlap.object = partial_func(_close_, self) win32file.CancelIo(self._handle) else: _close_(self, 0, 0)
def close(self): """Similar to 'close' of file descriptor. """ if self._handle: try: flags = win32pipe.GetNamedPipeInfo(self._handle)[0] except Exception: flags = 0 if flags & win32con.PIPE_SERVER_END: win32pipe.DisconnectNamedPipe(self._handle) # TODO: if pipe, need to call FlushFileBuffers? def _close_(rc, n): win32file.CloseHandle(self._handle) self._overlap = None if self._notifier: self._notifier.unregister(self._handle) self._handle = None self._read_result = self._write_result = None self._read_task = self._write_task = None self._buflist = [] if self._overlap.object: self._overlap.object = _close_ win32file.CancelIo(self._handle) else: _close_(0, 0)
def connect(self, address): win32pipe.WaitNamedPipe(address, self._timeout) handle = win32file.CreateFile( address, win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0, None, win32file.OPEN_EXISTING, cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT, 0) self.flags = win32pipe.GetNamedPipeInfo(handle)[0] self._handle = handle self._address = address
def __init__(self, name, pipe_type='server' or 'client', *, open_mode=win32pipe.PIPE_ACCESS_DUPLEX | win32file.FILE_FLAG_OVERLAPPED, pipe_mode=win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_NOWAIT, maxinstances=255, out_buffer_size=1000000, in_buffer_size=1000000, default_timeout=50, security_attrib=None): """An implementation of a file-like python object pipe https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx""" self.pipe_type = pipe_type self.name = name self.open_mode = open_mode self.pipe_mode = pipe_mode if pipe_type == 'server': self.handle = win32pipe.CreateNamedPipe( PIPE_ROOT + name, open_mode, # default PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED pipe_mode, # default PIPE_TYPE_BYTE|PIPE_NOWAIT maxinstances, # default 255 out_buffer_size, # default 1000000 in_buffer_size, # default 1000000 default_timeout, # default 50 security_attrib # default None ) elif pipe_type == 'client': # it doesn't matter what type of pipe the server is so long as we know the name self.handle = win32file.CreateFile( PIPE_ROOT + name, win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0, None, win32file.OPEN_EXISTING, 0, None) else: raise ValueError('pipe_type', ('server', 'client')) self.fd = msvcrt.open_osfhandle(self.handle, 0) self.is_connected = False self.flags, self.out_buffer_size, self.in_buffer_size, self.maxinstances = win32pipe.GetNamedPipeInfo( self.handle)
def connect(self, address): win32pipe.WaitNamedPipe(address, self._timeout) try: handle = win32file.CreateFile( address, win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0, None, win32file.OPEN_EXISTING, cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT, 0) except win32pipe.error as e: # See Remarks: # https://msdn.microsoft.com/en-us/library/aa365800.aspx if e.winerror == cERROR_PIPE_BUSY: # Another program or thread has grabbed our pipe instance # before we got to it. Wait for availability and attempt to # connect again. win32pipe.WaitNamedPipe(address, RETRY_WAIT_TIMEOUT) return self.connect(address) raise e self.flags = win32pipe.GetNamedPipeInfo(handle)[0] self._handle = handle self._address = address
def getnamedpipeinfo(phandle): """ returns pipe's flags, buffer sizes, and max instances @return (int, int, int, int) """ return (w32pipe.GetNamedPipeInfo(phandle))
def ListNamedPipes() -> Iterator[rdf_client.NamedPipe]: """Yields all named pipes available in the system.""" if platform.system() != "Windows": raise RuntimeError(f"Unsupported platform: {platform.system()}") # pylint: disable=g-import-not-at-top # pytype: disable=import-error import ctypes import ctypes.wintypes import win32api import win32file import win32pipe import winerror # pytype: enable=import-error # pylint: enable=g-import-not-at-top # The `GetNamedPipeHandleState` function provided by the `win32pipe` module is # broken (calling it results in invalid function exception). Hence, we need to # go to a lower level and use raw Windows API calls to get this information. # # https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-getnamedpipehandlestatew # pytype: disable=module-attr GetNamedPipeHandleStateW = ctypes.windll.kernel32.GetNamedPipeHandleStateW # pylint: disable=invalid-name # pytype: enable=module-attr GetNamedPipeHandleStateW.argtypes = [ ctypes.wintypes.HANDLE, ctypes.wintypes.LPDWORD, ctypes.wintypes.LPDWORD, ctypes.wintypes.LPDWORD, ctypes.wintypes.LPDWORD, ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD, ] GetNamedPipeHandleStateW.restype = ctypes.wintypes.BOOL # For some reason the `GetNamedPipeClientComputerName` function does not exist # in `win32pipe`. Hence, we implement a low-level wrapper for Windows API for # it ourselves. # # https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-getnamedpipeclientcomputernamew # pytype: disable=module-attr GetNamedPipeClientComputerNameW = ctypes.windll.kernel32.GetNamedPipeClientComputerNameW # pylint: disable=invalid-name # pytype: enable=module-attr GetNamedPipeClientComputerNameW.argtypes = [ ctypes.wintypes.HANDLE, ctypes.wintypes.LPWSTR, ctypes.wintypes.ULONG, ] GetNamedPipeClientComputerNameW.restype = ctypes.wintypes.BOOL # https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names for name in os.listdir(r"\\.\pipe"): pipe = rdf_client.NamedPipe() pipe.name = name try: handle = win32file.CreateFile(f"\\\\.\\pipe\\{name}", 0, 0, None, win32file.OPEN_EXISTING, 0, None) except win32file.error as error: # There might be some permission issues. We log the error and skip getting # pipe details, but still yield a result with at least the name filled-in. logging.error("Cannot open pipe '%s': %s", name, error) yield pipe continue with contextlib.closing(handle): try: pipe_info = win32pipe.GetNamedPipeInfo(handle) flags, in_buffer_size, out_buffer_size, max_instance_count = pipe_info pipe.flags = flags pipe.in_buffer_size = in_buffer_size pipe.out_buffer_size = out_buffer_size pipe.max_instance_count = max_instance_count except win32pipe.error as error: # Getting the information might fail (for whatever reason), but we don't # want to fail action execution as other probing calls might succeed. logging.error("Failed to get info about pipe '%s': '%s'", name, error) try: pipe.server_pid = win32pipe.GetNamedPipeServerProcessId(handle) except win32pipe.error as error: # See similar comment for `GetNamedPipeInfo` for more information. message = "Failed to get server pid of pipe '%s': '%s'" logging.error(message, name, error) try: pipe.client_pid = win32pipe.GetNamedPipeClientProcessId(handle) except win32pipe.error as error: # See similar comment for `GetNamedPipeInfo` for more information. message = "Failed to get client pid of pipe '%s': '%s'" logging.error(message, name, error) cur_instance_count = ctypes.wintypes.DWORD() status = GetNamedPipeHandleStateW( ctypes.wintypes.HANDLE(int(handle)), None, ctypes.byref(cur_instance_count), None, None, None, 0, ) if status == 0: # See similar comment for `GetNamedPipeInfo` for more information. error = win32api.GetLastError() logging.error("Failed to get state of pipe '%s': %s", name, error) else: pipe.cur_instance_count = cur_instance_count.value client_computer_name = (ctypes.wintypes.WCHAR * _COMPUTER_NAME_MAX_SIZE)() # pytype: disable=not-callable status = GetNamedPipeClientComputerNameW( ctypes.wintypes.HANDLE(int(handle)), client_computer_name, _COMPUTER_NAME_MAX_SIZE, ) if status == 0: # See similar comment for `GetNamedPipeInfo` for more information. error = win32api.GetLastError() # Not being able to get computer name of a local pipe is expected, there # is no need to log errors in such cases. if error != winerror.ERROR_PIPE_LOCAL: logging.error("Failed to get hostname of pipe '%s': %s", name, error) else: pipe.client_computer_name = client_computer_name.value yield pipe