18cc49becSPavel Labathfrom __future__ import print_function 28cc49becSPavel Labath 38cc49becSPavel Labathimport gdbremote_testcase 4*872b1da6SPavel Labathimport random 58cc49becSPavel Labathimport select 68cc49becSPavel Labathimport socket 78cc49becSPavel Labathfrom lldbsuite.test.decorators import * 88cc49becSPavel Labathfrom lldbsuite.test.lldbtest import * 9*872b1da6SPavel Labathfrom lldbgdbserverutils import Server 1085f025e5SPavel Labathimport lldbsuite.test.lldbplatformutil 1185f025e5SPavel Labath 1285f025e5SPavel Labathif lldbplatformutil.getHostPlatform() == "windows": 1385f025e5SPavel Labath import ctypes 1485f025e5SPavel Labath import ctypes.wintypes 1585f025e5SPavel Labath from ctypes.wintypes import (BOOL, DWORD, HANDLE, LPCWSTR, LPDWORD, LPVOID) 1685f025e5SPavel Labath 1785f025e5SPavel Labath kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) 1885f025e5SPavel Labath 1985f025e5SPavel Labath PIPE_ACCESS_INBOUND = 1 2085f025e5SPavel Labath FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000 2185f025e5SPavel Labath FILE_FLAG_OVERLAPPED = 0x40000000 2285f025e5SPavel Labath PIPE_TYPE_BYTE = 0 2385f025e5SPavel Labath PIPE_REJECT_REMOTE_CLIENTS = 8 2485f025e5SPavel Labath INVALID_HANDLE_VALUE = -1 2585f025e5SPavel Labath ERROR_ACCESS_DENIED = 5 2685f025e5SPavel Labath ERROR_IO_PENDING = 997 2785f025e5SPavel Labath 2885f025e5SPavel Labath 2985f025e5SPavel Labath class OVERLAPPED(ctypes.Structure): 3085f025e5SPavel Labath _fields_ = [("Internal", LPVOID), ("InternalHigh", LPVOID), ("Offset", 3185f025e5SPavel Labath DWORD), ("OffsetHigh", DWORD), ("hEvent", HANDLE)] 3285f025e5SPavel Labath 3385f025e5SPavel Labath def __init__(self): 3485f025e5SPavel Labath super(OVERLAPPED, self).__init__(Internal=0, InternalHigh=0, 3585f025e5SPavel Labath Offset=0, OffsetHigh=0, hEvent=None) 3685f025e5SPavel Labath LPOVERLAPPED = ctypes.POINTER(OVERLAPPED) 3785f025e5SPavel Labath 3885f025e5SPavel Labath CreateNamedPipe = kernel32.CreateNamedPipeW 3985f025e5SPavel Labath CreateNamedPipe.restype = HANDLE 4085f025e5SPavel Labath CreateNamedPipe.argtypes = (LPCWSTR, DWORD, DWORD, DWORD, DWORD, DWORD, 4185f025e5SPavel Labath DWORD, LPVOID) 4285f025e5SPavel Labath 4385f025e5SPavel Labath ConnectNamedPipe = kernel32.ConnectNamedPipe 4485f025e5SPavel Labath ConnectNamedPipe.restype = BOOL 4585f025e5SPavel Labath ConnectNamedPipe.argtypes = (HANDLE, LPOVERLAPPED) 4685f025e5SPavel Labath 4785f025e5SPavel Labath CreateEvent = kernel32.CreateEventW 4885f025e5SPavel Labath CreateEvent.restype = HANDLE 4985f025e5SPavel Labath CreateEvent.argtypes = (LPVOID, BOOL, BOOL, LPCWSTR) 5085f025e5SPavel Labath 5185f025e5SPavel Labath GetOverlappedResultEx = kernel32.GetOverlappedResultEx 5285f025e5SPavel Labath GetOverlappedResultEx.restype = BOOL 5385f025e5SPavel Labath GetOverlappedResultEx.argtypes = (HANDLE, LPOVERLAPPED, LPDWORD, DWORD, 5485f025e5SPavel Labath BOOL) 5585f025e5SPavel Labath 5685f025e5SPavel Labath ReadFile = kernel32.ReadFile 5785f025e5SPavel Labath ReadFile.restype = BOOL 5885f025e5SPavel Labath ReadFile.argtypes = (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) 5985f025e5SPavel Labath 6085f025e5SPavel Labath CloseHandle = kernel32.CloseHandle 6185f025e5SPavel Labath CloseHandle.restype = BOOL 6285f025e5SPavel Labath CloseHandle.argtypes = (HANDLE,) 6385f025e5SPavel Labath 6485f025e5SPavel Labath class Pipe(object): 6585f025e5SPavel Labath def __init__(self, prefix): 6685f025e5SPavel Labath while True: 6785f025e5SPavel Labath self.name = "lldb-" + str(random.randrange(1e10)) 6885f025e5SPavel Labath full_name = "\\\\.\\pipe\\" + self.name 6985f025e5SPavel Labath self._handle = CreateNamedPipe(full_name, PIPE_ACCESS_INBOUND | 7085f025e5SPavel Labath FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, 7185f025e5SPavel Labath PIPE_TYPE_BYTE | PIPE_REJECT_REMOTE_CLIENTS, 1, 4096, 7285f025e5SPavel Labath 4096, 0, None) 7385f025e5SPavel Labath if self._handle != INVALID_HANDLE_VALUE: 7485f025e5SPavel Labath break 7585f025e5SPavel Labath if ctypes.get_last_error() != ERROR_ACCESS_DENIED: 7685f025e5SPavel Labath raise ctypes.WinError(ctypes.get_last_error()) 7785f025e5SPavel Labath 7885f025e5SPavel Labath self._overlapped = OVERLAPPED() 7985f025e5SPavel Labath self._overlapped.hEvent = CreateEvent(None, True, False, None) 8085f025e5SPavel Labath result = ConnectNamedPipe(self._handle, self._overlapped) 8185f025e5SPavel Labath assert result == 0 8285f025e5SPavel Labath if ctypes.get_last_error() != ERROR_IO_PENDING: 8385f025e5SPavel Labath raise ctypes.WinError(ctypes.get_last_error()) 8485f025e5SPavel Labath 8585f025e5SPavel Labath def finish_connection(self, timeout): 8685f025e5SPavel Labath if not GetOverlappedResultEx(self._handle, self._overlapped, 8785f025e5SPavel Labath ctypes.byref(DWORD(0)), timeout*1000, True): 8885f025e5SPavel Labath raise ctypes.WinError(ctypes.get_last_error()) 8985f025e5SPavel Labath 9085f025e5SPavel Labath def read(self, size, timeout): 9185f025e5SPavel Labath buf = ctypes.create_string_buffer(size) 9285f025e5SPavel Labath if not ReadFile(self._handle, ctypes.byref(buf), size, None, 9385f025e5SPavel Labath self._overlapped): 9485f025e5SPavel Labath if ctypes.get_last_error() != ERROR_IO_PENDING: 9585f025e5SPavel Labath raise ctypes.WinError(ctypes.get_last_error()) 9685f025e5SPavel Labath read = DWORD(0) 9785f025e5SPavel Labath if not GetOverlappedResultEx(self._handle, self._overlapped, 9885f025e5SPavel Labath ctypes.byref(read), timeout*1000, True): 9985f025e5SPavel Labath raise ctypes.WinError(ctypes.get_last_error()) 10085f025e5SPavel Labath return buf.raw[0:read.value] 10185f025e5SPavel Labath 10285f025e5SPavel Labath def close(self): 10385f025e5SPavel Labath CloseHandle(self._overlapped.hEvent) 10485f025e5SPavel Labath CloseHandle(self._handle) 10585f025e5SPavel Labath 10685f025e5SPavel Labath 10785f025e5SPavel Labathelse: 10885f025e5SPavel Labath class Pipe(object): 10985f025e5SPavel Labath def __init__(self, prefix): 11085f025e5SPavel Labath self.name = os.path.join(prefix, "stub_port_number") 11185f025e5SPavel Labath os.mkfifo(self.name) 11285f025e5SPavel Labath self._fd = os.open(self.name, os.O_RDONLY | os.O_NONBLOCK) 11385f025e5SPavel Labath 11485f025e5SPavel Labath def finish_connection(self, timeout): 11585f025e5SPavel Labath pass 11685f025e5SPavel Labath 11785f025e5SPavel Labath def read(self, size, timeout): 11885f025e5SPavel Labath (readers, _, _) = select.select([self._fd], [], [], timeout) 11985f025e5SPavel Labath if self._fd not in readers: 12085f025e5SPavel Labath raise TimeoutError 12185f025e5SPavel Labath return os.read(self._fd, size) 12285f025e5SPavel Labath 12385f025e5SPavel Labath def close(self): 12485f025e5SPavel Labath os.close(self._fd) 1258cc49becSPavel Labath 1268cc49becSPavel Labath 1278cc49becSPavel Labathclass TestGdbRemoteConnection(gdbremote_testcase.GdbRemoteTestCaseBase): 1288cc49becSPavel Labath 1298cc49becSPavel Labath @skipIfRemote # reverse connect is not a supported use case for now 130a63daf69SPavel Labath def test_reverse_connect(self): 1318cc49becSPavel Labath # Reverse connect is the default connection method. 1328cc49becSPavel Labath self.connect_to_debug_monitor() 1338cc49becSPavel Labath # Verify we can do the handshake. If that works, we'll call it good. 134*872b1da6SPavel Labath self.do_handshake() 1358cc49becSPavel Labath 1368cc49becSPavel Labath @skipIfRemote 137a63daf69SPavel Labath def test_named_pipe(self): 1388cc49becSPavel Labath family, type, proto, _, addr = socket.getaddrinfo( 1398cc49becSPavel Labath self.stub_hostname, 0, proto=socket.IPPROTO_TCP)[0] 1408cc49becSPavel Labath self.sock = socket.socket(family, type, proto) 1418cc49becSPavel Labath self.sock.settimeout(self.DEFAULT_TIMEOUT) 1428cc49becSPavel Labath 1438cc49becSPavel Labath self.addTearDownHook(lambda: self.sock.close()) 1448cc49becSPavel Labath 14585f025e5SPavel Labath pipe = Pipe(self.getBuildDir()) 1468cc49becSPavel Labath 14785f025e5SPavel Labath self.addTearDownHook(lambda: pipe.close()) 1488cc49becSPavel Labath 1498cc49becSPavel Labath args = self.debug_monitor_extra_args 1508cc49becSPavel Labath if lldb.remote_platform: 1518cc49becSPavel Labath args += ["*:0"] 1528cc49becSPavel Labath else: 1538cc49becSPavel Labath args += ["localhost:0"] 1548cc49becSPavel Labath 15585f025e5SPavel Labath args += ["--named-pipe", pipe.name] 1568cc49becSPavel Labath 1578cc49becSPavel Labath server = self.spawnSubprocess( 1588cc49becSPavel Labath self.debug_monitor_exe, 1598cc49becSPavel Labath args, 1608cc49becSPavel Labath install_remote=False) 1618cc49becSPavel Labath 16285f025e5SPavel Labath pipe.finish_connection(self.DEFAULT_TIMEOUT) 16385f025e5SPavel Labath port = pipe.read(10, self.DEFAULT_TIMEOUT) 1648cc49becSPavel Labath # Trim null byte, convert to int 1658cc49becSPavel Labath addr = (addr[0], int(port[:-1])) 1668cc49becSPavel Labath self.sock.connect(addr) 167*872b1da6SPavel Labath self._server = Server(self.sock, server) 1688cc49becSPavel Labath 1698cc49becSPavel Labath # Verify we can do the handshake. If that works, we'll call it good. 170*872b1da6SPavel Labath self.do_handshake() 171