Facilitate the merge
[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 TargetProcessLauncher CustomTargetProcessLauncher {
25                         get; set;
26                 }
27
28                 public delegate Process ProcessLauncher (ProcessStartInfo info);
29                 public delegate ITargetProcess TargetProcessLauncher (ProcessStartInfo info);
30         }
31
32         public class VirtualMachineManager
33         {
34                 private delegate VirtualMachine LaunchCallback (ITargetProcess p, ProcessStartInfo info, Socket socket);
35                 private delegate VirtualMachine ListenCallback (Socket dbg_sock, Socket con_sock); 
36
37                 internal VirtualMachineManager () {
38                 }
39
40                 public static VirtualMachine LaunchInternal (Process p, ProcessStartInfo info, Socket socket)
41                 {
42                         return LaunchInternal (new ProcessWrapper (p), info, socket);
43                 }
44                         
45                 public static VirtualMachine LaunchInternal (ITargetProcess p, ProcessStartInfo info, Socket socket) {
46                         Socket accepted = null;
47                         try {
48                                 accepted = socket.Accept ();
49                         } catch (Exception) {
50                                 throw;
51                         }
52
53                         Connection conn = new Connection (accepted);
54
55                         VirtualMachine vm = new VirtualMachine (p, conn);
56
57                         if (info.RedirectStandardOutput)
58                                 vm.StandardOutput = p.StandardOutput;
59                         
60                         if (info.RedirectStandardError)
61                                 vm.StandardError = p.StandardError;
62
63                         conn.EventHandler = new EventHandler (vm);
64
65                         vm.connect ();
66
67                         return vm;
68                 }
69
70                 public static IAsyncResult BeginLaunch (ProcessStartInfo info, AsyncCallback callback, LaunchOptions options = null) {
71                         if (info == null)
72                                 throw new ArgumentNullException ("info");
73
74                         Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
75                         socket.Bind (new IPEndPoint (IPAddress.Loopback, 0));
76                         socket.Listen (1000);
77                         IPEndPoint ep = (IPEndPoint) socket.LocalEndPoint;
78
79                         // We need to inject our arguments into the psi
80                         info.Arguments = string.Format ("{0} --debug --debugger-agent=transport=dt_socket,address={1}:{2}{3} {4}", 
81                                                                 options == null || !options.Valgrind ? "" : info.FileName,
82                                                                 ep.Address,
83                                                                 ep.Port,
84                                                                 options == null || options.AgentArgs == null ? "" : "," + options.AgentArgs,
85                                                                 info.Arguments);
86
87                         if (options != null && options.Valgrind)
88                                 info.FileName = "valgrind";
89                                 
90                         ITargetProcess p;
91                         if (options != null && options.CustomProcessLauncher != null)
92                                 p = new ProcessWrapper (options.CustomProcessLauncher (info));
93                         else if (options != null && options.CustomTargetProcessLauncher != null)
94                                 p = options.CustomTargetProcessLauncher (info);
95                         else
96                                 p = new ProcessWrapper (Process.Start (info));
97                         
98                         p.Exited += delegate (object sender, EventArgs eargs) {
99                                 socket.Close ();
100                         };
101
102                         LaunchCallback c = new LaunchCallback (LaunchInternal);
103                         return c.BeginInvoke (p, info, socket, callback, socket);
104                 }
105
106                 public static VirtualMachine EndLaunch (IAsyncResult asyncResult) {
107                         if (asyncResult == null)
108                                 throw new ArgumentNullException ("asyncResult");
109
110                         if (!asyncResult.IsCompleted)
111                                 asyncResult.AsyncWaitHandle.WaitOne ();
112
113                         AsyncResult async = (AsyncResult) asyncResult;
114                         LaunchCallback cb = (LaunchCallback) async.AsyncDelegate;
115                         return cb.EndInvoke (asyncResult);
116                 }
117
118                 public static VirtualMachine Launch (ProcessStartInfo info, LaunchOptions options = null) {
119                         return EndLaunch (BeginLaunch (info, null, options));
120                 }
121
122                 public static VirtualMachine Launch (string[] args, LaunchOptions options = null) {
123                         ProcessStartInfo pi = new ProcessStartInfo ("mono");
124                         pi.Arguments = String.Join (" ", args);
125
126                         return Launch (pi, options);
127                 }
128                         
129                 public static VirtualMachine ListenInternal (Socket dbg_sock, Socket con_sock) {
130                         Socket con_acc = null;
131                         Socket dbg_acc = null;
132
133                         if (con_sock != null) {
134                                 try {
135                                         con_acc = con_sock.Accept ();
136                                 } catch (Exception) {
137                                         try {
138                                                 dbg_sock.Close ();
139                                         } catch {}
140                                         throw;
141                                 }
142                         }
143                                                 
144                         try {
145                                 dbg_acc = dbg_sock.Accept ();
146                         } catch (Exception) {
147                                 if (con_sock != null) {
148                                         try {
149                                                 con_sock.Close ();
150                                                 con_acc.Close ();
151                                         } catch {}
152                                 }
153                                 throw;
154                         }
155
156                         if (con_sock != null) {
157                                 con_sock.Disconnect (false);
158                                 con_sock.Close ();
159                         }
160
161                         dbg_sock.Disconnect (false);
162                         dbg_sock.Close ();
163
164                         Connection conn = new Connection (dbg_acc);
165
166                         VirtualMachine vm = new VirtualMachine (null, conn);
167
168                         if (con_acc != null) {
169                                 vm.StandardOutput = new StreamReader (new NetworkStream (con_acc));
170                                 vm.StandardError = null;
171                         }
172
173                         conn.EventHandler = new EventHandler (vm);
174
175                         vm.connect ();
176
177                         return vm;
178                 }
179
180                 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, AsyncCallback callback) {
181                         return BeginListen (dbg_ep, null, callback);
182                 }
183
184                 public static IAsyncResult BeginListen (IPEndPoint dbg_ep, IPEndPoint con_ep, AsyncCallback callback) {
185                         Socket dbg_sock = null;
186                         Socket con_sock = null;
187
188                         dbg_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
189                         dbg_sock.Bind (dbg_ep);
190                         dbg_sock.Listen (1000);
191
192                         if (con_ep != null) {
193                                 con_sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
194                                 con_sock.Bind (con_ep);
195                                 con_sock.Listen (1000);
196                         }
197                         
198                         ListenCallback c = new ListenCallback (ListenInternal);
199                         return c.BeginInvoke (dbg_sock, con_sock, callback, con_sock ?? dbg_sock);
200                 }
201
202                 public static VirtualMachine EndListen (IAsyncResult asyncResult) {
203                         if (asyncResult == null)
204                                 throw new ArgumentNullException ("asyncResult");
205
206                         if (!asyncResult.IsCompleted)
207                                 asyncResult.AsyncWaitHandle.WaitOne ();
208
209                         AsyncResult async = (AsyncResult) asyncResult;
210                         ListenCallback cb = (ListenCallback) async.AsyncDelegate;
211                         return cb.EndInvoke (asyncResult);
212                 }
213
214                 public static VirtualMachine Listen (IPEndPoint dbg_ep, IPEndPoint con_ep = null) { 
215                         return EndListen (BeginListen (dbg_ep, con_ep, null));
216                 }
217
218                 /*
219                  * Connect to a virtual machine listening at the specified address.
220                  */
221                 public static VirtualMachine Connect (IPEndPoint endpoint) {
222                         if (endpoint == null)
223                                 throw new ArgumentNullException ("endpoint");
224
225                         Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
226                         socket.Connect (endpoint);
227
228                         Connection conn = new Connection (socket);
229
230                         VirtualMachine vm = new VirtualMachine (null, conn);
231
232                         conn.EventHandler = new EventHandler (vm);
233
234                         vm.connect ();
235
236                         return vm;
237                 }
238         }
239 }