2 using System.Collections.Generic;
3 using System.Diagnostics;
6 using System.Net.Sockets;
7 using System.Runtime.Remoting.Messaging;
9 namespace Mono.Debugger.Soft
11 public class LaunchOptions {
12 public string AgentArgs {
16 public bool Valgrind {
20 public ProcessLauncher CustomProcessLauncher {
24 public TargetProcessLauncher CustomTargetProcessLauncher {
28 public delegate Process ProcessLauncher (ProcessStartInfo info);
29 public delegate ITargetProcess TargetProcessLauncher (ProcessStartInfo info);
32 public class VirtualMachineManager
34 private delegate VirtualMachine LaunchCallback (ITargetProcess p, ProcessStartInfo info, Socket socket);
35 private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock);
36 private delegate VirtualMachine ConnectCallback (Socket dbg_sock, Socket con_sock, IPEndPoint dbg_ep, IPEndPoint con_ep);
38 internal VirtualMachineManager () {
41 public static VirtualMachine LaunchInternal (Process p, ProcessStartInfo info, Socket socket)
43 return LaunchInternal (new ProcessWrapper (p), info, socket);
46 public static VirtualMachine LaunchInternal (ITargetProcess p, ProcessStartInfo info, Socket socket) {
47 Socket accepted = null;
49 accepted = socket.Accept ();
54 Connection conn = new TcpConnection (accepted);
56 VirtualMachine vm = new VirtualMachine (p, conn);
58 if (info.RedirectStandardOutput)
59 vm.StandardOutput = p.StandardOutput;
61 if (info.RedirectStandardError)
62 vm.StandardError = p.StandardError;
64 conn.EventHandler = new EventHandler (vm);
71 public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback)
73 return BeginLaunch (info, callback, null);
76 public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options)
79 throw new ArgumentNullException ("info");
81 Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
82 socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
84 IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
86 // We need to inject our arguments into the psi
87 info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}",
88 options == null || !options.Valgrind ? "" : info.FileName,
91 options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
94 if (options != null && options.Valgrind)
95 info.FileName = "valgrind";
96 info.UseShellExecute = false;
99 if (options != null && options.CustomProcessLauncher != null)
100 p = new ProcessWrapper (options.CustomProcessLauncher (info));
101 else if (options != null && options.CustomTargetProcessLauncher != null)
102 p = options.CustomTargetProcessLauncher (info);
104 p = new ProcessWrapper (Process.Start (info));
106 p.Exited += delegate (object sender, EventArgs eargs) {
110 LaunchCallback c = new LaunchCallback (LaunchInternal);
111 return c.BeginInvoke (p, info, socket, callback, socket);
114 public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
115 if (asyncResult == null)
116 throw new ArgumentNullException ("asyncResult");
118 if (!asyncResult.IsCompleted)
119 asyncResult.AsyncWaitHandle.WaitOne ();
121 AsyncResult result = (AsyncResult) asyncResult;
122 LaunchCallback cb = (LaunchCallback) result.AsyncDelegate;
123 return cb.EndInvoke (asyncResult);
126 public static VirtualMachine Launch (ProcessStartInfo info)
128 return Launch (info, null);
131 public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options)
133 return EndLaunch (BeginLaunch (info, null, options));
136 public static VirtualMachine Launch (string[] args)
138 return Launch (args, null);
141 public static VirtualMachine Launch (string[] args, LaunchOptions options)
143 ProcessStartInfo pi = new ProcessStartInfo ("mono");
144 pi.Arguments = String.Join (" ", args);
146 return Launch (pi, options);
149 public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
150 Socket con_acc = null;
151 Socket dbg_acc = null;
153 if (con_sock != null) {
155 con_acc = con_sock.Accept ();
156 } catch (Exception) {
165 dbg_acc = dbg_sock.Accept ();
166 } catch (Exception) {
167 if (con_sock != null) {
176 if (con_sock != null) {
177 if (con_sock.Connected)
178 con_sock.Disconnect (false);
182 if (dbg_sock.Connected)
183 dbg_sock.Disconnect (false);
186 Connection transport = new TcpConnection (dbg_acc);
187 StreamReader console = con_acc != null? new StreamReader (new NetworkStream (con_acc)) : null;
189 return Connect (transport, console, null);
192 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
193 return BeginListen (dbg_ep, null, callback);
196 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback)
198 int dbg_port, con_port;
199 return BeginListen (dbg_ep, con_ep, callback, out dbg_port, out con_port);
202 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback,
203 out int dbg_port, out int con_port)
205 dbg_port = con_port = 0;
207 Socket dbg_sock = null;
208 Socket con_sock = null;
210 dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
211 dbg_sock.Bind (dbg_ep);
212 dbg_sock.Listen (1000);
213 dbg_port = ((IPEndPoint) dbg_sock.LocalEndPoint).Port;
215 if (con_ep != null) {
216 con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
217 con_sock.Bind (con_ep);
218 con_sock.Listen (1000);
219 con_port = ((IPEndPoint) con_sock.LocalEndPoint).Port;
222 ListenCallback c = new ListenCallback (ListenInternal);
223 return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
226 public static VirtualMachine EndListen (IAsyncResult asyncResult) {
227 if (asyncResult == null)
228 throw new ArgumentNullException ("asyncResult");
230 if (!asyncResult.IsCompleted)
231 asyncResult.AsyncWaitHandle.WaitOne ();
233 AsyncResult result = (AsyncResult) asyncResult;
234 ListenCallback cb = (ListenCallback) result.AsyncDelegate;
235 return cb.EndInvoke (asyncResult);
238 public static VirtualMachine Listen (IPEndPoint dbg_ep)
240 return Listen (dbg_ep, null);
243 public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep)
245 return EndListen (BeginListen (dbg_ep, con_ep, null));
249 * Connect to a virtual machine listening at the specified address.
251 public static VirtualMachine Connect (IPEndPoint endpoint) {
252 return Connect (endpoint, null);
255 public static VirtualMachine Connect (IPEndPoint endpoint, IPEndPoint consoleEndpoint) {
256 if (endpoint == null)
257 throw new ArgumentNullException ("endpoint");
259 return EndConnect (BeginConnect (endpoint, consoleEndpoint, null));
262 public static VirtualMachine ConnectInternal (Socket dbg_sock, Socket con_sock, IPEndPoint dbg_ep, IPEndPoint con_ep) {
263 if (con_sock != null) {
265 con_sock.Connect (con_ep);
266 } catch (Exception) {
275 dbg_sock.Connect (dbg_ep);
276 } catch (Exception) {
277 if (con_sock != null) {
285 Connection transport = new TcpConnection (dbg_sock);
286 StreamReader console = con_sock != null? new StreamReader (new NetworkStream (con_sock)) : null;
288 return Connect (transport, console, null);
291 public static IAsyncResult BeginConnect (IPEndPoint dbg_ep, AsyncCallback callback) {
292 return BeginConnect (dbg_ep, null, callback);
295 public static IAsyncResult BeginConnect (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
296 Socket dbg_sock = null;
297 Socket con_sock = null;
299 dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
301 if (con_ep != null) {
302 con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
305 ConnectCallback c = new ConnectCallback (ConnectInternal);
306 return c.BeginInvoke (dbg_sock, con_sock, dbg_ep, con_ep, callback, con_sock ?? dbg_sock);
309 public static VirtualMachine EndConnect (IAsyncResult asyncResult) {
310 if (asyncResult == null)
311 throw new ArgumentNullException ("asyncResult");
313 if (!asyncResult.IsCompleted)
314 asyncResult.AsyncWaitHandle.WaitOne ();
316 AsyncResult result = (AsyncResult) asyncResult;
317 ConnectCallback cb = (ConnectCallback) result.AsyncDelegate;
318 return cb.EndInvoke (asyncResult);
321 public static void CancelConnection (IAsyncResult asyncResult)
323 ((Socket)asyncResult.AsyncState).Close ();
326 public static VirtualMachine Connect (Connection transport, StreamReader standardOutput, StreamReader standardError)
328 VirtualMachine vm = new VirtualMachine (null, transport);
330 vm.StandardOutput = standardOutput;
331 vm.StandardError = standardError;
333 transport.EventHandler = new EventHandler (vm);