public override SbListener Create(GrpcConnection connection, string name) { var instance = new SbListenerStub(name); Instances.Add(instance); return(instance); }
public async Task DeviceServiceTest() { var serverBuilder = new RpcServiceDefinitionsBuilder(); serverBuilder.RegisterService <IThermostatService>(); var host = new GrpcServer(serverBuilder, null, this.options); host.AddEndPoint(CreateEndPoint()); host.Start(); try { var serviceImpl = new ThermostatServiceImpl(); using (var publishScope = host.PublishInstance(serviceImpl)) { var objectId = publishScope.Value.ObjectId; GrpcConnection connection = this.CreateGrpcConnection(); var clientService = connection.GetServiceInstance <IThermostatServiceClient>(objectId); var acoId = clientService.DeviceAcoId; var baseClientService = (IDeviceServiceClient)clientService; var acoId2 = baseClientService.DeviceAcoId; Assert.AreEqual(acoId, acoId2); } } finally { await host.ShutdownAsync(); } }
public void StartPreGame(LaunchOption launchOption, bool rgpEnabled, bool renderdocEnabled, SshTarget target, out GrpcConnection grpcConnection, out ITransportSession transportSession) { lock (thisLock) { grpcConnection = null; this.transportSession = transportSession = transportSessionFactory.Create(); if (transportSession == null) { Trace.WriteLine("Unable to start the debug transport, invalid session."); throw new YetiDebugTransportException(ErrorStrings.FailedToStartTransport); } if (!LaunchPreGameProcesses(launchOption, rgpEnabled, renderdocEnabled, target)) { Stop(ExitReason.Unknown); throw new YetiDebugTransportException( "Failed to launch all needed pre-game processes"); } Trace.WriteLine("Started debug transport. Session ID: " + transportSession.GetSessionId()); // The grpcConnection is created during the launch of one of the processes. grpcConnection = this.grpcConnection; } }
public void SetUp() { var callInvokerFactory = new PipeCallInvokerFactory(); mainThreadContext = new FakeMainThreadContext(); taskContext = mainThreadContext.JoinableTaskContext; connection = new GrpcConnection(taskContext.Factory, callInvokerFactory.Create()); }
public override SbDebugger Create( GrpcConnection connection, bool sourceInitFiles, TimeSpan retryWaitTime) { if (waitTime > retryWaitTime) { return(null); } return(Debugger); }
public ServerInfo(PipeServiceBinder server, PipeCallInvoker callInvoker, GrpcConnection connection, RemoteObjectStores stores, LldbMockFactories mockFactories) { Server = server; CallInvoker = callInvoker; Connection = connection; Stores = stores; MockFactories = mockFactories; }
SbListener CreateListener(GrpcConnection grpcConnection) { var lldbListener = _lldbListenerFactory.Create(grpcConnection, "LLDBWorker Listener"); if (lldbListener == null) { throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToCreateDebugListener); } return(lldbListener); }
// Exits and disposes of all processes, the TransportSession, and GrpcConnection. public void Stop(ExitReason exitReason) { lock (thisLock) { // Stop the grpc connection first because it depends on the the grpc server process // that is managed by the process manager. grpcConnection?.Shutdown(); grpcConnection = null; grpcCallInvoker?.Dispose(); grpcCallInvoker = null; transportSession?.Dispose(); transportSession = null; processManager?.StopAll(exitReason); processManager = null; } }
SbPlatform CreateRemotePlatform(GrpcConnection grpcConnection, SbDebugger debugger) { string platformName; if (debugger.IsPlatformAvailable(_remoteLldbPlatformName)) { _stadiaPlatformAvailable = true; platformName = _remoteLldbPlatformName; } else { platformName = _fallbackRemoteLldbPlatformName; } return(_lldbPlatformFactory.Create(platformName, grpcConnection)); }
public void SetUp() { var factory = new GrpcPlatformFactoryFake(null); factory.AddFakeProcess("linux-remote", "myGame", 2222); factory.AddFakeProcess("linux-remote", "ssh", 443244); factory.AddFakeProcess("linux-remote", "blah", 4545); var callInvokerFactory = new PipeCallInvokerFactory(); var grpcConnection = new GrpcConnection(new JoinableTaskContext().Factory, callInvokerFactory.Create()); platform = factory.Create("linux-remote", grpcConnection); connectOptions = new GrpcPlatformConnectOptionsFactory() .Create("http://any/url"); shellCommandFactory = new GrpcPlatformShellCommandFactory(); }
private ServerInfo CreateServer( PipeCallInvokerFactory callInvokerFactory, GrpcConnectionFactory connectionFactory) { PipeCallInvoker callInvoker = callInvokerFactory.Create(); GrpcConnection connection = connectionFactory.Create(callInvoker); string[] inPipeHandles, outPipeHandles; callInvoker.GetClientPipeHandles(out inPipeHandles, out outPipeHandles); // Note: The client's out handles are the server's in handles and vice versa. PipeServiceBinder server = new PipeServiceBinder(outPipeHandles, inPipeHandles); var stores = new RemoteObjectStores(); var mockFactories = new LldbMockFactories(); BindServices(server, stores, mockFactories); server.Start(); return(new ServerInfo(server, callInvoker, connection, stores, mockFactories)); }
public void SetUp() { var taskContext = new JoinableTaskContext(); PipeCallInvokerFactory callInvokerFactory = new PipeCallInvokerFactory(); PipeCallInvoker callInvoker = callInvokerFactory.Create(); _grpcConnection = new GrpcConnection(taskContext.Factory, callInvoker); _callback = Substitute.For <IDebugEventCallback2>(); _debuggerOptions = new YetiVSI.DebuggerOptions.DebuggerOptions { [DebuggerOption.CLIENT_LOGGING] = DebuggerOptionState.DISABLED }; _libPaths = new HashSet <string> { "some/path", "some/other/path", _gameBinary }; _programId = Guid.Empty; _task = Substitute.For <ICancelable>(); _process = new DebugProcessStub(enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, _pid); _fileSystem = new MockFileSystem(); _debugEngine = Substitute.For <IDebugEngine3>(); _gameLaunch = Substitute.For <IVsiGameLaunch>(); }
ProcessStartData CreateDebuggerGrpcServerProcessStartData() { var startInfo = new ProcessStartInfo { FileName = Path.Combine(YetiConstants.RootDir, YetiConstants.DebuggerGrpcServerExecutable), }; // (internal): grpcCallInvoker must be created right before the process is created! // If it is created before the other processes are created, they'll hold on to the // pipes and they won't get closed if the GRPC server shuts down. Action <ProcessStartInfo> beforeStart = (processStartInfo) => { grpcCallInvoker = grpcCallInvokerFactory.Create(); grpcConnection = grpcConnectionFactory.Create(grpcCallInvoker); grpcConnection.RpcException += StopWithException; grpcConnection.AsyncRpcCompleted += onAsyncRpcCompleted; grpcCallInvoker.GetClientPipeHandles(out string[] inPipeHandles, out string[] outPipeHandles); // Note: The server's input pipes are the client's output pipes and vice versa. processStartInfo.Arguments = $"-i {string.Join(",", outPipeHandles)} " + $"-o {string.Join(",", inPipeHandles)}"; }; // Dispose client handles right after start. This is necessary so that pipes are closed // when the server exits. Action afterStart = () => { grpcCallInvoker.DisposeLocalCopyOfClientPipeHandles(); }; var rootDir = YetiConstants.RootDir; #if USE_LOCAL_PYTHON_AND_TOOLCHAIN // This is gated by the <DeployPythonAndToolchainDependencies> project setting to speed // up the build. var pythonRoot = File.ReadAllText(Path.Combine(rootDir, "local_python_dir.txt")).Trim(); var toolchainDir = File.ReadAllText(Path.Combine(rootDir, "local_toolchain_dir.txt")) .Trim(); var lldbSitePackagesDir = Path.Combine(toolchainDir, "windows", "lib", "site-packages"); var libLldbDir = Path.Combine(toolchainDir, "windows", "bin"); // Quick sanity check that all directories exist. var notFoundDir = !Directory.Exists(pythonRoot) ? pythonRoot : !Directory.Exists(lldbSitePackagesDir) ? lldbSitePackagesDir : !Directory.Exists(libLldbDir) ? libLldbDir : null; if (!string.IsNullOrEmpty(notFoundDir)) { // Note: This error is only shown to internal VSI devs, not to external devs. throw new YetiDebugTransportException( "You have set the <DeployPythonAndToolchainDependencies> project setting to " + $"False to speed up deployment, but the Python/toolchain dir {notFoundDir} " + "moved. Either fix the wrong directory (preferred) or set " + "<DeployPythonAndToolchainDependencies> to False."); } #else var pythonRoot = Path.Combine(rootDir, "Python3"); var lldbSitePackagesDir = Path.Combine(YetiConstants.LldbDir, "site-packages"); var libLldbDir = Path.Combine(YetiConstants.LldbDir, "bin"); #endif // Search paths for dLLs. startInfo.Environment["PATH"] = string.Join(";", new string[] { rootDir, pythonRoot, libLldbDir }); // Search paths for Python files. startInfo.Environment["PYTHONPATH"] = string.Join(";", new string[] { Path.Combine(pythonRoot, "Lib"), lldbSitePackagesDir }); // Do not display console windows when launching processes. In our case, // we do not want the scp process to show the console window. startInfo.Environment["LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"] = "true"; Trace.WriteLine($"Starting {startInfo.FileName} with" + Environment.NewLine + $"\tPATH={(startInfo.Environment["PATH"])}" + Environment.NewLine + $"\tPYTHONPATH={(startInfo.Environment["PYTHONPATH"])}"); // Use the directory with the binary as working directory. Normally it doesn't matter, // because the server doesn't load any files via relative paths and the dependent DLLs // are available via PATH and PYTHONPATH. However when debugging or just running the // extension from Visual Studio the working directory is set to the output build // directory. The working directory has precedence for loading DLLs, so liblldb.dll is // picked up from the build output directory, NOT the deployed extension. startInfo.WorkingDirectory = Path.GetDirectoryName(startInfo.FileName); // Uncomment to enable GRPC debug logging for DebuggerGrpcServer.exe. // This is currently very verbose, and you will most likely want to restrict logging to // a subset. // //lldbGrpcStartInfo.EnvironmentVariables["GRPC_TRACE"] = "all"; //lldbGrpcStartInfo.EnvironmentVariables["GRPC_VERBOSITY"] = "DEBUG"; return(new ProcessStartData("lldb grpc server", startInfo, beforeStart: beforeStart, afterStart: afterStart)); }
public async Task <ILldbAttachedProgram> LaunchAsync( ICancelable task, IDebugProcess2 process, Guid programId, uint?attachPid, DebuggerOptions.DebuggerOptions debuggerOptions, HashSet <string> libPaths, GrpcConnection grpcConnection, int localDebuggerPort, string targetIpAddress, int targetPort, IDebugEventCallback2 callback) { var launchSucceeded = false; Stopwatch launchTimer = Stopwatch.StartNew(); // This should be the first request to the DebuggerGrpcServer. Providing a retry wait // time allows us to connect to a DebuggerGrpcServer that is slow to start. Note that // we postpone sourcing .lldbinit until we are done with our initialization so that // the users can override our defaults. var lldbDebugger = _lldbDebuggerFactory.Create(grpcConnection, false, TimeSpan.FromSeconds(10)); if (lldbDebugger == null) { throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToCreateDebugger); } if (debuggerOptions[DebuggerOption.CLIENT_LOGGING] == DebuggerOptionState.ENABLED) { lldbDebugger.EnableLog("lldb", new List <string> { "default", "module" }); // TODO: Disable 'dwarf' logs until we can determine why this // causes LLDB to hang. // lldbDebugger.EnableLog("dwarf", new List<string> { "default" }); } if (_fastExpressionEvaluation) { lldbDebugger.EnableFastExpressionEvaluation(); } lldbDebugger.SetDefaultLLDBSettings(); // Apply .lldbinit after we set our settings so that the user can override our // defaults with a custom .lldbinit. LoadLocalLldbInit(lldbDebugger); // Add exec search paths, so that LLDB can find the executable and any dependent // libraries. If LLDB is able to find the files locally, it won't try to download // them from the remote server, saving valuable time on attach. foreach (string path in libPaths) { lldbDebugger.SetLibrarySearchPath(path); } lldbDebugger.SetAsync(true); SbPlatform lldbPlatform; switch (_launchOption) { case LaunchOption.AttachToGame: // Fall through. case LaunchOption.LaunchGame: lldbPlatform = CreateRemotePlatform(grpcConnection, lldbDebugger); if (lldbPlatform == null) { throw new AttachException(VSConstants.E_FAIL, ErrorStrings.FailedToCreateLldbPlatform); } task.ThrowIfCancellationRequested(); Trace.WriteLine("Attempting to connect debugger"); task.Progress.Report("Connecting to debugger"); string connectRemoteUrl = $"{_lldbConnectUrl}:{localDebuggerPort}"; string connectRemoteArgument = CreateConnectRemoteArgument(connectRemoteUrl, targetIpAddress, targetPort); SbPlatformConnectOptions lldbConnectOptions = _lldbPlatformConnectOptionsFactory.Create(connectRemoteArgument); IAction debugerWaitAction = _actionRecorder.CreateToolAction(ActionType.DebugWaitDebugger); bool TryConnectRemote() { if (lldbPlatform.ConnectRemote(lldbConnectOptions).Success()) { return(true); } VerifyGameIsReady(debugerWaitAction); return(false); } try { debugerWaitAction.Record(() => RetryWithTimeout( task, TryConnectRemote, _launchRetryDelay, _launchTimeout, launchTimer)); } catch (TimeoutException e) { throw new AttachException( VSConstants.E_ABORT, ErrorStrings.FailedToConnectDebugger(lldbConnectOptions.GetUrl()), e); } Trace.WriteLine("LLDB successfully connected"); break; case LaunchOption.AttachToCore: lldbPlatform = _lldbPlatformFactory.Create(_localLldbPlatformName, grpcConnection); if (lldbPlatform == null) { throw new AttachException(VSConstants.E_FAIL, ErrorStrings.FailedToCreateLldbPlatform); } break; default: throw new AttachException(VSConstants.E_ABORT, ErrorStrings.InvalidLaunchOption( _launchOption.ToString())); } lldbDebugger.SetSelectedPlatform(lldbPlatform); task.ThrowIfCancellationRequested(); task.Progress.Report("Debugger is attaching (this can take a while)"); RemoteTarget lldbTarget = null; if (_launchOption == LaunchOption.LaunchGame && !string.IsNullOrEmpty(_executableFullPath)) { var createExecutableTargetAction = _actionRecorder.CreateToolAction(ActionType.DebugCreateExecutableTarget); createExecutableTargetAction.Record( () => lldbTarget = CreateTarget(lldbDebugger, _executableFullPath)); } else { lldbTarget = CreateTarget(lldbDebugger, ""); } var lldbListener = CreateListener(grpcConnection); // This is required to catch breakpoint change events. lldbTarget.AddListener(lldbListener, EventType.STATE_CHANGED); var listenerSubscriber = new LldbListenerSubscriber(lldbListener); var eventHandler = new EventHandler <FileUpdateReceivedEventArgs>( (s, e) => ListenerSubscriberOnFileUpdateReceived(task, e)); listenerSubscriber.FileUpdateReceived += eventHandler; listenerSubscriber.Start(); try { if (_launchOption == LaunchOption.AttachToCore) { var loadCoreAction = _actionRecorder.CreateToolAction(ActionType.DebugLoadCore); SbProcess lldbDebuggerProcess = null; loadCoreAction.Record(() => lldbDebuggerProcess = LoadCore(lldbTarget, loadCoreAction)); await _taskContext.Factory.SwitchToMainThreadAsync(); return(_attachedProgramFactory.Create( process, programId, _debugEngine, callback, lldbDebugger, lldbTarget, listenerSubscriber, lldbDebuggerProcess, lldbDebugger.GetCommandInterpreter(), true, new NullExceptionManager(), _moduleSearchLogHolder, remotePid: 0)); } // Get process ID. uint processId = 0; switch (_launchOption) { case LaunchOption.AttachToGame: if (!attachPid.HasValue) { throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToRetrieveProcessId); } processId = attachPid.Value; break; case LaunchOption.LaunchGame: // Since we have no way of knowing when the remote process actually // starts, try a few times to get the pid. IAction debugWaitAction = _actionRecorder.CreateToolAction(ActionType.DebugWaitProcess); bool TryGetRemoteProcessId() { if (GetRemoteProcessId(_executableFileName, lldbPlatform, out processId)) { return(true); } VerifyGameIsReady(debugWaitAction); return(false); } try { debugWaitAction.Record(() => RetryWithTimeout( task, TryGetRemoteProcessId, _launchRetryDelay, _launchTimeout, launchTimer)); } catch (TimeoutException e) { throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToRetrieveProcessId, e); } break; } Trace.WriteLine("Attaching to pid " + processId); var debugAttachAction = _actionRecorder.CreateToolAction(ActionType.DebugAttach); SbProcess debuggerProcess = null; debugAttachAction.Record(() => { var moduleFileLoadRecorder = _moduleFileLoadRecorderFactory.Create(debugAttachAction); moduleFileLoadRecorder.RecordBeforeLoad(Array.Empty <SbModule>()); debuggerProcess = lldbTarget.AttachToProcessWithID(lldbListener, processId, out SbError lldbError); if (lldbError.Fail()) { throw new AttachException( VSConstants.E_ABORT, GetLldbAttachErrorDetails(lldbError, lldbPlatform, processId)); } RecordModules(lldbTarget, moduleFileLoadRecorder); }); var exceptionManager = _exceptionManagerFactory.Create(debuggerProcess); await _taskContext.Factory.SwitchToMainThreadAsync(); ILldbAttachedProgram attachedProgram = _attachedProgramFactory.Create( process, programId, _debugEngine, callback, lldbDebugger, lldbTarget, listenerSubscriber, debuggerProcess, lldbDebugger.GetCommandInterpreter(), false, exceptionManager, _moduleSearchLogHolder, processId); launchSucceeded = true; return(attachedProgram); } finally { // clean up the SBListener subscriber listenerSubscriber.FileUpdateReceived -= eventHandler; // stop the SBListener subscriber completely if the game failed to launch if (!launchSucceeded) { listenerSubscriber.Stop(); } } }
public override SbPlatform Create(string platformName, GrpcConnection grpcConnection) => new SbPlatformFake(platformName, _platformProcesses.Where(p => p.PlatformName == platformName), _connectRecorder, _processCommandToOutput, _connectRemoteStatuses, _runStatuses);
/// <summary> /// TODO: Use factories instead of using this.connnectionType. /// </summary> /// <param name="serviceDefinitionsProvider"></param> /// <param name="proxyDefinitionsProvider"></param> /// <returns></returns> protected (IRpcServerHost, IRpcChannel) CreateServerAndConnection( IRpcServiceDefinitionsProvider serviceDefinitionsProvider = null, Action <RpcServerOptions> configServerOptions = null, Action <RpcClientOptions> configClientOptions = null, Action <IServiceCollection> configureServices = null) { var rpcServerId = RpcServerId.NewId(); var serverOptions = new RpcServerOptions { Serializer = this.serializer }; var clientOptions = new RpcClientOptions { Serializer = this.serializer }; configServerOptions?.Invoke(serverOptions); configClientOptions?.Invoke(clientOptions); IServiceProvider services = GetServiceProvider(configureServices); switch (this.ConnectionType) { case RpcConnectionType.LightweightTcp: case RpcConnectionType.LightweightSslTcp: { var host = new LightweightRpcServer(rpcServerId, serviceDefinitionsProvider, services, serverOptions, this.LightweightOptions, loggerFactory: services.GetService <ILoggerFactory>()); SslServerOptions sslServerOptions = null; if (this.ConnectionType == RpcConnectionType.LightweightSslTcp) { sslServerOptions = new SslServerOptions(new X509Certificate2(TestCertificates.ServerPFXPath, "1111")); } host.AddEndPoint(new TcpRpcEndPoint("127.0.0.1", TcpTestPort, false, sslServerOptions)); SslClientOptions sslClientOptions = null; if (this.ConnectionType == RpcConnectionType.LightweightSslTcp) { sslClientOptions = new SslClientOptions { RemoteCertificateValidationCallback = this.ValidateTestCertificate }; } var connection = new TcpRpcConnection( new RpcConnectionInfo("TCP", new Uri($"lightweight.tcp://127.0.0.1:{TcpTestPort}"), rpcServerId), sslClientOptions, clientOptions.AsImmutable(), this.LightweightOptions); return(host, connection); } case RpcConnectionType.LightweightNamedPipe: { var server = new LightweightRpcServer(rpcServerId, serviceDefinitionsProvider, services, serverOptions, this.LightweightOptions, loggerFactory: services.GetService <ILoggerFactory>()); server.AddEndPoint(new NamedPipeRpcEndPoint("testpipe")); var connection = new NamedPipeRpcConnection( new RpcConnectionInfo(new Uri("lightweight.pipe://./testpipe")), clientOptions.AsImmutable(), this.LightweightOptions); return(server, connection); } case RpcConnectionType.LightweightInproc: { Pipe requestPipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.ThreadPool)); Pipe responsePipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.Inline)); var host = new LightweightRpcServer(rpcServerId, serviceDefinitionsProvider, services, serverOptions, loggerFactory: services.GetService <ILoggerFactory>()); host.AddEndPoint(new InprocRpcEndPoint(new DirectDuplexPipe(requestPipe.Reader, responsePipe.Writer))); var connection = new InprocRpcConnection(new RpcConnectionInfo("Direct", new Uri("direct:localhost"), rpcServerId), new DirectDuplexPipe(responsePipe.Reader, requestPipe.Writer), clientOptions.AsImmutable()); return(host, connection); } case RpcConnectionType.Grpc: { var host = new GrpcServer(rpcServerId, serviceDefinitionsProvider, services, serverOptions); host.AddEndPoint(GrpcCoreFullStackTestsBase.CreateEndPoint()); var connection = new GrpcConnection( new RpcConnectionInfo("TCP", new Uri($"grpc://localhost:{GrpcCoreFullStackTestsBase.GrpcTestPort}"), rpcServerId), TestCertificates.GrpcSslCredentials, clientOptions.AsImmutable()); return(host, connection); } #if PLAT_NET_GRPC case RpcConnectionType.NetGrpc: { var server = CreateNetGrpcServer(serviceDefinitionsProvider, rpcServerId, serverOptions, configureServices); //var host = new GrpcServer(rpcServerId, serviceDefinitionsBuilder, null, options); //host.AddEndPoint(GrpcCoreFullStackTestsBase.CreateEndPoint()); var handler = new System.Net.Http.HttpClientHandler(); handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => { return(true); }; var channelOptions = new GrpcNet.Client.GrpcChannelOptions() { HttpClient = new System.Net.Http.HttpClient(handler), DisposeHttpClient = true }; var connection = new NetGrpcConnection( new RpcConnectionInfo("net-grpc", new Uri($"grpc://localhost:{GrpcCoreFullStackTestsBase.GrpcTestPort}"), rpcServerId), clientOptions.AsImmutable(), channelOptions); return(server, connection); } #endif } throw new NotSupportedException(); }