using System.IO;
using System.Net;
using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
namespace Mono.Debugger
{
public class LaunchOptions {
- public string Runtime {
- get; set;
- }
-
- public bool RedirectStandardOutput {
- get; set;
- }
-
- public bool RedirectStandardError {
- get; set;
- }
-
public string AgentArgs {
get; set;
}
public class VirtualMachineManager
{
+ private delegate VirtualMachine LaunchCallback (Process p, Socket socket);
+ private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock);
+
internal VirtualMachineManager () {
}
- /*
- * Launch a new virtual machine with the provided arguments.
- */
- public static VirtualMachine Launch (string[] args, LaunchOptions options = null) {
- if (args == null)
- throw new ArgumentNullException ("args");
- Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
- socket.Listen (1000);
-
- IPEndPoint endPoint = (IPEndPoint)socket.LocalEndPoint;
- string addressString = endPoint.Address.ToString () + ":" + endPoint.Port.ToString ();
-
- string runtime = "mono";
- bool valgrind = options != null && options.Valgrind;
-
- string extra_args = "";
-
- if (options != null && options.Runtime != null)
- runtime = options.Runtime;
- if (options != null && options.AgentArgs != null)
- extra_args = "," + options.AgentArgs;
-
- string agent_args = "--debug --debugger-agent=transport=dt_socket,address=" + addressString + extra_args;
- if (valgrind)
- agent_args = runtime + " " + agent_args;
-
- ProcessStartInfo start_info = new ProcessStartInfo ();
- start_info.FileName = valgrind ? "valgrind" : runtime;
- start_info.Arguments = agent_args + " " + String.Join (" ", args);
- start_info.UseShellExecute = false;
- if (options != null && options.RedirectStandardOutput)
- start_info.RedirectStandardOutput = true;
- if (options != null && options.RedirectStandardError)
- start_info.RedirectStandardError = true;
- Process p = Process.Start (start_info);
- bool exited = false;
- /* Handle the debuggee exiting so we don't block in Accept () forever */
- p.Exited += delegate (object sender, EventArgs eargs) {
- exited = true;
- socket.Close ();
- };
-
- /*
- * Wait until we are connected to the debuggee so the caller gets
- * back a fully usable vm object.
- * FIXME: This might block forever.
- */
+ public static VirtualMachine LaunchInternal (Process p, Socket socket) {
Socket accepted = null;
try {
accepted = socket.Accept ();
} catch (ObjectDisposedException) {
- if (exited)
- throw new IOException ("Debuggee process exited.");
- else
- throw;
+ throw;
}
Connection conn = new Connection (accepted);
VirtualMachine vm = new VirtualMachine (p, conn);
- if (options != null && options.RedirectStandardOutput)
+ if (p.StartInfo.RedirectStandardOutput)
vm.StandardOutput = p.StandardOutput;
- if (options != null && options.RedirectStandardError)
+ if (p.StartInfo.RedirectStandardError)
vm.StandardError = p.StandardError;
conn.EventHandler = new EventHandler (vm);
return vm;
}
- /*
- * Wait for a virtual machine to connect at the specified address.
- */
- public static VirtualMachine Listen (IPAddress address, int debugger_port, int console_port) {
- if (address == null)
- throw new ArgumentNullException ("address");
+ public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options = null) {
+ if (info == null)
+ throw new ArgumentNullException ("info");
- IPEndPoint dbg_ep = new IPEndPoint (address, debugger_port);
- IPEndPoint con_ep = new IPEndPoint (address, console_port);
+ Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
+ socket.Listen (1000);
+ IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
+
+ // We need to inject our arguments into the psi
+ info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}",
+ options == null || !options.Valgrind ? "" : info.FileName,
+ ep.Address,
+ ep.Port,
+ options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
+ info.Arguments);
+
+ if (options != null && options.Valgrind)
+ info.FileName = "valgrind";
+
+ Process p = Process.Start (info);
+
+ p.Exited += delegate (object sender, EventArgs eargs) {
+ socket.Close ();
+ };
- Socket con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- Socket dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- con_sock.Bind (con_ep);
- dbg_sock.Bind (dbg_ep);
- con_sock.Listen (1000);
- dbg_sock.Listen (1000);
+ LaunchCallback c = new LaunchCallback (LaunchInternal);
+ return c.BeginInvoke (p, socket, callback, socket);
+ }
- return Listen (con_sock, dbg_sock);
+ public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
+
+ AsyncResult async = (AsyncResult) asyncResult;
+ LaunchCallback cb = (LaunchCallback) async.AsyncDelegate;
+ return cb.EndInvoke (asyncResult);
}
- public static VirtualMachine Listen (Socket con_sock, Socket dbg_sock) {
- /*
- * FIXME: This might block forever.
- */
- Socket con_accepted = con_sock.Accept ();
- Socket dbg_accepted = dbg_sock.Accept ();
+ public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options = null) {
+ return EndLaunch (BeginLaunch (info, null, null));
+ }
+
+ public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
+ Socket con_acc = null;
+ Socket dbg_acc = null;
+
+ if (con_sock != null) {
+ try {
+ con_acc = con_sock.Accept ();
+ } catch (ObjectDisposedException) {
+ try {
+ dbg_sock.Close ();
+ } catch {}
+ throw;
+ }
+ }
+
+ try {
+ dbg_acc = dbg_sock.Accept ();
+ } catch (ObjectDisposedException) {
+ if (con_sock != null) {
+ try {
+ con_sock.Close ();
+ con_acc.Close ();
+ } catch {}
+ }
+ throw;
+ }
+
+ if (con_sock != null) {
+ con_sock.Disconnect (false);
+ con_sock.Close ();
+ }
- con_sock.Disconnect (false);
dbg_sock.Disconnect (false);
- con_sock.Close ();
dbg_sock.Close ();
- Connection conn = new Connection (dbg_accepted);
+ Connection conn = new Connection (dbg_acc);
VirtualMachine vm = new VirtualMachine (null, conn);
- vm.StandardOutput = new StreamReader (new NetworkStream (con_accepted));
- vm.StandardError = null;
+ if (con_acc != null) {
+ vm.StandardOutput = new StreamReader (new NetworkStream (con_acc));
+ vm.StandardError = null;
+ }
+
conn.EventHandler = new EventHandler (vm);
vm.connect ();
return vm;
}
- /*
- * Wait for a virtual machine to connect at the specified address.
- */
- public static VirtualMachine Listen (IPEndPoint endpoint) {
- if (endpoint == null)
- throw new ArgumentNullException ("endpoint");
-
- Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- socket.Bind (endpoint);
- socket.Listen (1000);
+ public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
+ return BeginListen (dbg_ep, null, callback);
+ }
- /*
- * FIXME: This might block forever.
- */
- Socket accepted = socket.Accept ();
+ public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
+ Socket dbg_sock = null;
+ Socket con_sock = null;
- socket.Disconnect (false);
- socket.Close ();
+ dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ dbg_sock.Bind (dbg_ep);
+ dbg_sock.Listen (1000);
- Connection conn = new Connection (accepted);
+ if (con_ep != null) {
+ con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ con_sock.Bind (con_ep);
+ con_sock.Listen (1000);
+ }
+
+ ListenCallback c = new ListenCallback (ListenInternal);
+ return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
+ }
- VirtualMachine vm = new VirtualMachine (null, conn);
+ public static VirtualMachine EndListen (IAsyncResult asyncResult) {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
- conn.EventHandler = new EventHandler (vm);
+ if (!asyncResult.IsCompleted)
+ asyncResult.AsyncWaitHandle.WaitOne ();
- vm.connect ();
+ AsyncResult async = (AsyncResult) asyncResult;
+ ListenCallback cb = (ListenCallback) async.AsyncDelegate;
+ return cb.EndInvoke (asyncResult);
+ }
- return vm;
+ public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep = null) {
+ return EndListen (BeginListen (dbg_ep, con_ep, null));
}
/*
return vm;
}
- }
+ }
}