/// <summary> /// Connect to an existing emulator process /// </summary> /// <returns>Success indication and error message.</returns> public async Task <StartResult> StartAsync() { int port; if (this.portConfig.Port != 0) { port = this.portConfig.Port; } else { var portString = Environment.GetEnvironmentVariable(Util.X3270Port); if (portString == null) { return(new StartResult(Util.X3270Port + " not found in the environment")); } // Parse it. ushort port16; if (!ushort.TryParse(portString, out port16)) { return(new StartResult("Invalid " + Util.X3270Port + " in the environment")); } port = port16; } var result = await SessionUtil.TryConnect(port, this.portConfig.ConnectRetryMsec).ConfigureAwait(continueOnCapturedContext: false); if (result.Success) { this.client = result.Client; return(new StartResult()); } else { return(new StartResult(result.FailReason)); } }
/// <summary> /// Start a new emulator process. Asynchronous version. /// </summary> /// <returns>Success/failure and failure reason.</returns> /// <exception cref="InvalidOperationException">Arguments are too long.</exception> public async Task <StartResult> StartAsync() { using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true); socket.Bind(new IPEndPoint(IPAddress.Any, 0)); int port = ((IPEndPoint)socket.LocalEndPoint).Port; // Start with basic arguments: // -utf8 UTF-8 mode // -model n Model number // -scriptportonce Make sure the emulator exists if the socket connection breaks var arguments = string.Format("-minversion {0} -utf8 -model {1} -scriptportonce", MinVersion, this.processConfig.Model); // Add arbitrary extra options. if (this.processConfig.ExtraOptions != null) { arguments += " " + string.Join(" ", this.processConfig.ExtraOptions.Select(o => o.Quote())); } // Build up the parameters for ws3270. var info = new ProcessStartInfo(this.processConfig.ProcessName); info.UseShellExecute = false; info.CreateNoWindow = true; info.RedirectStandardError = true; info.RedirectStandardOutput = true; info.Arguments = string.Empty; // Put special unit test options first, intended to throw off the "-scriptport"-first logic below. if (this.processConfig.TestFirstOptions != null) { info.Arguments = this.processConfig.TestFirstOptions; } // It's important to put "-scriptport" first, because the Mock server looks for it and ignores everything else. info.Arguments += info.Arguments.JoinNonEmpty(" ", string.Format("-scriptport {0}", port)); info.Arguments += info.Arguments.JoinNonEmpty(" ", arguments); // Check for argument overflow. // At some point, we could automatically put most arguments into a temporary session file, but for now, // we blow up, so arguments aren't silently ignored. var argsMax = (Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1) ? 32699 : 2080; if (this.processConfig.ProcessName.Length + 1 + info.Arguments.Length > argsMax) { throw new InvalidOperationException("Arguments too long"); } Util.Log("ProcessSession Start: ProcessName '{0}', arguments '{1}'", this.processConfig.ProcessName, info.Arguments); // Try starting it. try { this.process = Process.Start(info); } catch (System.ComponentModel.Win32Exception e) { // Typically Start errors are Win32 errors return(new StartResult(e.Message)); } catch (Exception e) { return(new StartResult(string.Format("Caught exception {0}", e))); } var result = await SessionUtil.TryConnect(port, this.processConfig.ConnectRetryMsec).ConfigureAwait(continueOnCapturedContext: false); if (!result.Success) { var emulatorErrorMessage = this.GetErrorOutput(result.FailReason); this.ZapProcess(); return(new StartResult(emulatorErrorMessage)); } else { this.client = result.Client; return(new StartResult()); } } }