2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.Debugger.Soft / Mono.Debugger.Soft / VirtualMachineManager.cs
blob932963473e6d0d2adc381281263c3aa84bc99cb5
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Net;
6 using System.Net.Sockets;
7 using System.Runtime.Remoting.Messaging;
9 namespace Mono.Debugger.Soft
11 public class LaunchOptions {
12 public string AgentArgs {
13 get; set;
16 public bool Valgrind {
17 get; set;
20 public ProcessLauncher CustomProcessLauncher {
21 get; set;
24 public delegate Process ProcessLauncher (ProcessStartInfo info);
27 public class VirtualMachineManager
29 private delegate VirtualMachine LaunchCallback (Process p, Socket socket);
30 private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock);
32 internal VirtualMachineManager () {
35 public static VirtualMachine LaunchInternal (Process p, Socket socket) {
36 Socket accepted = null;
37 try {
38 accepted = socket.Accept ();
39 } catch (Exception) {
40 throw;
43 Connection conn = new Connection (accepted);
45 VirtualMachine vm = new VirtualMachine (p, conn);
47 if (p.StartInfo.RedirectStandardOutput)
48 vm.StandardOutput = p.StandardOutput;
50 if (p.StartInfo.RedirectStandardError)
51 vm.StandardError = p.StandardError;
53 conn.EventHandler = new EventHandler (vm);
55 vm.connect ();
57 return vm;
60 public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options = null) {
61 if (info == null)
62 throw new ArgumentNullException ("info");
64 Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
65 socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
66 socket.Listen (1000);
67 IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
69 // We need to inject our arguments into the psi
70 info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}",
71 options == null || !options.Valgrind ? "" : info.FileName,
72 ep.Address,
73 ep.Port,
74 options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
75 info.Arguments);
77 if (options != null && options.Valgrind)
78 info.FileName = "valgrind";
80 Process p;
81 if (options != null && options.CustomProcessLauncher != null)
82 p = options.CustomProcessLauncher (info);
83 else
84 p = Process.Start (info);
86 p.Exited += delegate (object sender, EventArgs eargs) {
87 socket.Close ();
90 LaunchCallback c = new LaunchCallback (LaunchInternal);
91 return c.BeginInvoke (p, socket, callback, socket);
94 public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
95 if (asyncResult == null)
96 throw new ArgumentNullException ("asyncResult");
98 if (!asyncResult.IsCompleted)
99 asyncResult.AsyncWaitHandle.WaitOne ();
101 AsyncResult async = (AsyncResult) asyncResult;
102 LaunchCallback cb = (LaunchCallback) async.AsyncDelegate;
103 return cb.EndInvoke (asyncResult);
106 public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options = null) {
107 return EndLaunch (BeginLaunch (info, null, options));
110 public static VirtualMachine Launch (string[] args, LaunchOptions options = null) {
111 ProcessStartInfo pi = new ProcessStartInfo ("mono");
112 pi.Arguments = String.Join (" ", args);
114 return Launch (pi, options);
117 public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
118 Socket con_acc = null;
119 Socket dbg_acc = null;
121 if (con_sock != null) {
122 try {
123 con_acc = con_sock.Accept ();
124 } catch (Exception) {
125 try {
126 dbg_sock.Close ();
127 } catch {}
128 throw;
132 try {
133 dbg_acc = dbg_sock.Accept ();
134 } catch (Exception) {
135 if (con_sock != null) {
136 try {
137 con_sock.Close ();
138 con_acc.Close ();
139 } catch {}
141 throw;
144 if (con_sock != null) {
145 con_sock.Disconnect (false);
146 con_sock.Close ();
149 dbg_sock.Disconnect (false);
150 dbg_sock.Close ();
152 Connection conn = new Connection (dbg_acc);
154 VirtualMachine vm = new VirtualMachine (null, conn);
156 if (con_acc != null) {
157 vm.StandardOutput = new StreamReader (new NetworkStream (con_acc));
158 vm.StandardError = null;
161 conn.EventHandler = new EventHandler (vm);
163 vm.connect ();
165 return vm;
168 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
169 return BeginListen (dbg_ep, null, callback);
172 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
173 Socket dbg_sock = null;
174 Socket con_sock = null;
176 dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
177 dbg_sock.Bind (dbg_ep);
178 dbg_sock.Listen (1000);
180 if (con_ep != null) {
181 con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
182 con_sock.Bind (con_ep);
183 con_sock.Listen (1000);
186 ListenCallback c = new ListenCallback (ListenInternal);
187 return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
190 public static VirtualMachine EndListen (IAsyncResult asyncResult) {
191 if (asyncResult == null)
192 throw new ArgumentNullException ("asyncResult");
194 if (!asyncResult.IsCompleted)
195 asyncResult.AsyncWaitHandle.WaitOne ();
197 AsyncResult async = (AsyncResult) asyncResult;
198 ListenCallback cb = (ListenCallback) async.AsyncDelegate;
199 return cb.EndInvoke (asyncResult);
202 public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep = null) {
203 return EndListen (BeginListen (dbg_ep, con_ep, null));
207 * Connect to a virtual machine listening at the specified address.
209 public static VirtualMachine Connect (IPEndPoint endpoint) {
210 if (endpoint == null)
211 throw new ArgumentNullException ("endpoint");
213 Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
214 socket.Connect (endpoint);
216 Connection conn = new Connection (socket);
218 VirtualMachine vm = new VirtualMachine (null, conn);
220 conn.EventHandler = new EventHandler (vm);
222 vm.connect ();
224 return vm;