New tests.
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / VirtualMachineManager.cs
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;
8
9 namespace Mono.Debugger.Soft
10 {
11         public class LaunchOptions {
12                 public string AgentArgs {
13                         get; set;
14                 }
15
16                 public bool Valgrind {
17                         get; set;
18                 }
19                 
20                 public ProcessLauncher CustomProcessLauncher {
21                         get; set;
22                 }
23
24                 public delegate IProcess ProcessLauncher (ProcessStartInfo info);
25         }
26
27         public class VirtualMachineManager
28         {
29                 private delegate VirtualMachine LaunchCallback (IProcess p, ProcessStartInfo info, Socket socket);
30                 private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock); 
31
32                 internal VirtualMachineManager () {
33                 }
34
35                 public static VirtualMachine LaunchInternal (IProcess p, ProcessStartInfo info, Socket socket) {
36                         Socket accepted = null;
37                         try {
38                                 accepted = socket.Accept ();
39                         } catch (Exception) {
40                                 throw;
41                         }
42
43                         Connection conn = new Connection (accepted);
44
45                         VirtualMachine vm = new VirtualMachine (p, conn);
46
47                         if (info.RedirectStandardOutput)
48                                 vm.StandardOutput = p.StandardOutput;
49                         
50                         if (info.RedirectStandardError)
51                                 vm.StandardError = p.StandardError;
52
53                         conn.EventHandler = new EventHandler (vm);
54
55                         vm.connect ();
56
57                         return vm;
58                 }
59
60                 public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options = null) {
61                         if (info == null)
62                                 throw new ArgumentNullException ("info");
63
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;
68
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);
76
77                         if (options != null && options.Valgrind)
78                                 info.FileName = "valgrind";
79                                 
80                         IProcess p;
81                         if (options != null && options.CustomProcessLauncher != null)
82                                 p = options.CustomProcessLauncher (info);
83                         else
84                                 p = new ProcessWrapper (Process.Start (info));
85                         
86                         p.Exited += delegate (object sender, EventArgs eargs) {
87                                 socket.Close ();
88                         };
89
90                         LaunchCallback c = new LaunchCallback (LaunchInternal);
91                         return c.BeginInvoke (p, info, socket, callback, socket);
92                 }
93
94                 public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
95                         if (asyncResult == null)
96                                 throw new ArgumentNullException ("asyncResult");
97
98                         if (!asyncResult.IsCompleted)
99                                 asyncResult.AsyncWaitHandle.WaitOne ();
100
101                         AsyncResult async = (AsyncResult) asyncResult;
102                         LaunchCallback cb = (LaunchCallback) async.AsyncDelegate;
103                         return cb.EndInvoke (asyncResult);
104                 }
105
106                 public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options = null) {
107                         return EndLaunch (BeginLaunch (info, null, options));
108                 }
109
110                 public static VirtualMachine Launch (string[] args, LaunchOptions options = null) {
111                         ProcessStartInfo pi = new ProcessStartInfo ("mono");
112                         pi.Arguments = String.Join (" ", args);
113
114                         return Launch (pi, options);
115                 }
116                         
117                 public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
118                         Socket con_acc = null;
119                         Socket dbg_acc = null;
120
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;
129                                 }
130                         }
131                                                 
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 {}
140                                 }
141                                 throw;
142                         }
143
144                         if (con_sock != null) {
145                                 con_sock.Disconnect (false);
146                                 con_sock.Close ();
147                         }
148
149                         dbg_sock.Disconnect (false);
150                         dbg_sock.Close ();
151
152                         Connection conn = new Connection (dbg_acc);
153
154                         VirtualMachine vm = new VirtualMachine (null, conn);
155
156                         if (con_acc != null) {
157                                 vm.StandardOutput = new StreamReader (new NetworkStream (con_acc));
158                                 vm.StandardError = null;
159                         }
160
161                         conn.EventHandler = new EventHandler (vm);
162
163                         vm.connect ();
164
165                         return vm;
166                 }
167
168                 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
169                         return BeginListen (dbg_ep, null, callback);
170                 }
171
172                 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
173                         Socket dbg_sock = null;
174                         Socket con_sock = null;
175
176                         dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
177                         dbg_sock.Bind (dbg_ep);
178                         dbg_sock.Listen (1000);
179
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);
184                         }
185                         
186                         ListenCallback c = new ListenCallback (ListenInternal);
187                         return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
188                 }
189
190                 public static VirtualMachine EndListen (IAsyncResult asyncResult) {
191                         if (asyncResult == null)
192                                 throw new ArgumentNullException ("asyncResult");
193
194                         if (!asyncResult.IsCompleted)
195                                 asyncResult.AsyncWaitHandle.WaitOne ();
196
197                         AsyncResult async = (AsyncResult) asyncResult;
198                         ListenCallback cb = (ListenCallback) async.AsyncDelegate;
199                         return cb.EndInvoke (asyncResult);
200                 }
201
202                 public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep = null) { 
203                         return EndListen (BeginListen (dbg_ep, con_ep, null));
204                 }
205
206                 /*
207                  * Connect to a virtual machine listening at the specified address.
208                  */
209                 public static VirtualMachine Connect (IPEndPoint endpoint) {
210                         if (endpoint == null)
211                                 throw new ArgumentNullException ("endpoint");
212
213                         Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
214                         socket.Connect (endpoint);
215
216                         Connection conn = new Connection (socket);
217
218                         VirtualMachine vm = new VirtualMachine (null, conn);
219
220                         conn.EventHandler = new EventHandler (vm);
221
222                         vm.connect ();
223
224                         return vm;
225                 }
226         }
227 }