~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.Debugger.Soft/MonoDevelop.Debugger.Soft/RemoteSoftDebuggerSession.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// 
2
 
// RemoteSoftDebuggerSession.cs
3
 
//  
4
 
// Author:
5
 
//       Michael Hutchinson <mhutchinson@novell.com>
6
 
// 
7
 
// Copyright (c) 2009 Novell, Inc.
8
 
// 
9
 
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
 
// of this software and associated documentation files (the "Software"), to deal
11
 
// in the Software without restriction, including without limitation the rights
12
 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 
// copies of the Software, and to permit persons to whom the Software is
14
 
// furnished to do so, subject to the following conditions:
15
 
// 
16
 
// The above copyright notice and this permission notice shall be included in
17
 
// all copies or substantial portions of the Software.
18
 
// 
19
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 
// THE SOFTWARE.
26
 
 
27
 
using System;
28
 
using Mono.Debugger.Soft;
29
 
using Mono.Debugging;
30
 
using Mono.Debugging.Client;
31
 
using System.Threading;
32
 
using System.Diagnostics;
33
 
using System.IO;
34
 
using System.Net.Sockets;
35
 
using System.Net;
36
 
using System.Collections.Generic;
37
 
using System.Reflection;
38
 
using MonoDevelop.Core;
39
 
using Mono.Debugging.Soft;
40
 
 
41
 
namespace MonoDevelop.Debugger.Soft
42
 
{
43
 
 
44
 
        public abstract class RemoteSoftDebuggerSession : SoftDebuggerSession
45
 
        {
46
 
                ProcessInfo[] procs;
47
 
                Gtk.Dialog dialog;
48
 
                string appName;
49
 
                Func<bool> retryConnection;
50
 
                
51
 
                /// <summary>Subclasses must implement this to start the session </summary>
52
 
                protected override void OnRun (DebuggerStartInfo startInfo)
53
 
                {
54
 
                        throw new NotImplementedException ();
55
 
                }
56
 
                
57
 
                /// <summary>Starts the debugger listening for a connection over TCP/IP</summary>
58
 
                protected void StartListening (RemoteDebuggerStartInfo dsi)
59
 
                {
60
 
                        IPEndPoint dbgEP, conEP;
61
 
                        PreConnectionInit (dsi, out dbgEP, out conEP);
62
 
                        
63
 
                        var callback = HandleConnectionCallbackErrors (ListenCallback);
64
 
                        OnConnecting (VirtualMachineManager.BeginListen (dbgEP, conEP, callback));
65
 
                        ShowConnectingDialog (dsi);
66
 
                }
67
 
                
68
 
                /// <summary>Starts the debugger connecting to a remote IP</summary>
69
 
                protected void StartConnecting (RemoteDebuggerStartInfo dsi, int maxAttempts, int timeBetweenAttempts)
70
 
                {
71
 
                        if (timeBetweenAttempts < 0 || timeBetweenAttempts > 10000)
72
 
                                throw new ArgumentException ("timeBetweenAttempts");
73
 
                        
74
 
                        IPEndPoint dbgEP, conEP;
75
 
                        PreConnectionInit (dsi, out dbgEP, out conEP);
76
 
                        
77
 
                        var callback = HandleConnectionCallbackErrors (ConnectCallback);
78
 
                        
79
 
                        retryConnection = () => {
80
 
                                if (maxAttempts == 1 || Exited) {
81
 
                                        return false;
82
 
                                }
83
 
                                if (maxAttempts > 1)
84
 
                                        maxAttempts--;
85
 
                                try {
86
 
                                        if (timeBetweenAttempts > 0)
87
 
                                                System.Threading.Thread.Sleep (timeBetweenAttempts);
88
 
                                        
89
 
                                        OnConnecting (VirtualMachineManager.BeginConnect (dbgEP, conEP, callback));
90
 
                                } catch (Exception ex2) {
91
 
                                        retryConnection = null;
92
 
                                        OnConnectionError (ex2);
93
 
                                        return false;
94
 
                                }
95
 
                                return true;
96
 
                        };
97
 
                        
98
 
                        ShowConnectingDialog (dsi);
99
 
                        
100
 
                        OnConnecting (VirtualMachineManager.BeginConnect (dbgEP, conEP, callback));
101
 
                }
102
 
                
103
 
                void PreConnectionInit (RemoteDebuggerStartInfo dsi, out IPEndPoint dbgEP, out IPEndPoint conEP)
104
 
                {
105
 
                        if (appName != null)
106
 
                                throw new InvalidOperationException ("Cannot initialize connection more than once");
107
 
                        
108
 
                        appName = dsi.AppName;
109
 
                        RegisterUserAssemblies (dsi.UserAssemblyNames);
110
 
                        
111
 
                        dbgEP = new IPEndPoint (dsi.Address, dsi.DebugPort);
112
 
                        conEP = dsi.RedirectOutput? new IPEndPoint (dsi.Address, dsi.OutputPort) : null;
113
 
                        
114
 
                        if (!String.IsNullOrEmpty (dsi.LogMessage))
115
 
                                LogWriter (false, dsi.LogMessage + "\n");
116
 
                }
117
 
                
118
 
                protected override void OnConnectionError (Exception ex)
119
 
                {
120
 
                        if (retryConnection != null) {
121
 
                                var sx = ex as SocketException;
122
 
                                if (sx != null) {
123
 
                                        bool retry = sx.ErrorCode == 10061; //connection refused
124
 
                                        if (retry && retryConnection ())
125
 
                                                return;
126
 
                                }
127
 
                                retryConnection = null;
128
 
                        }
129
 
                        
130
 
                        base.OnConnectionError (ex);
131
 
                }
132
 
                
133
 
                void PressOk ()
134
 
                {
135
 
                        Gtk.Application.Invoke (delegate {
136
 
                                if (dialog != null)
137
 
                                        dialog.Respond (Gtk.ResponseType.Ok);
138
 
                        });
139
 
                }
140
 
                
141
 
                //get rid of the dialog if there's an exception while connecting
142
 
                protected override bool HandleException (Exception ex)
143
 
                {
144
 
                        if (dialog != null) {
145
 
                                Gtk.Application.Invoke (delegate {
146
 
                                        if (dialog != null)
147
 
                                                dialog.Respond (Gtk.ResponseType.Ok);
148
 
                                });
149
 
                        }
150
 
                        return base.HandleException (ex);
151
 
                }
152
 
                
153
 
                void ListenCallback (IAsyncResult ar)
154
 
                {
155
 
                        HandleConnection (VirtualMachineManager.EndListen (ar));
156
 
                        PressOk ();
157
 
                }
158
 
                
159
 
                void ConnectCallback (IAsyncResult ar)
160
 
                {
161
 
                        HandleConnection (VirtualMachineManager.EndConnect (ar));
162
 
                        retryConnection = null;
163
 
                        PressOk ();
164
 
                }
165
 
                
166
 
                //[Obsolete]
167
 
                protected virtual string GetListenMessage (RemoteDebuggerStartInfo dsi)
168
 
                {
169
 
                        return GettextCatalog.GetString ("Waiting for debugger to connect...");
170
 
                }
171
 
                
172
 
                protected virtual string GetConnectingMessage (RemoteDebuggerStartInfo dsi)
173
 
                {
174
 
                        //ignore the Obsolete warning
175
 
                        #pragma warning disable 0612
176
 
                        return GetListenMessage (dsi);
177
 
                        #pragma warning restore 0612
178
 
                }
179
 
                
180
 
                void ShowConnectingDialog (RemoteDebuggerStartInfo dsi)
181
 
                {
182
 
                        string message = GetConnectingMessage (dsi);
183
 
                        
184
 
                        Gtk.Application.Invoke (delegate {
185
 
                                if (VirtualMachine != null || Exited)
186
 
                                        return;
187
 
                                
188
 
                                dialog = new Gtk.Dialog () {
189
 
                                        Title = "Waiting for debugger"
190
 
                                };
191
 
                                
192
 
                                var label = new Gtk.Alignment (0.5f, 0.5f, 1f, 1f) {
193
 
                                        Child = new Gtk.Label (message),
194
 
                                        BorderWidth = 12
195
 
                                };
196
 
                                dialog.VBox.PackStart (label);
197
 
                                label.ShowAll ();       
198
 
                                
199
 
                                dialog.AddButton ("Cancel", Gtk.ResponseType.Cancel);
200
 
                                
201
 
                                int response = MonoDevelop.Ide.MessageService.ShowCustomDialog (dialog);
202
 
                                
203
 
                                dialog = null;
204
 
                                
205
 
                                if (response != (int) Gtk.ResponseType.Ok) {
206
 
                                        EndSession ();
207
 
                                }
208
 
                        });
209
 
                }
210
 
                
211
 
                protected override void EndSession ()
212
 
                {
213
 
                        if (dialog != null) {
214
 
                                Gtk.Application.Invoke (delegate {
215
 
                                        if (dialog != null)
216
 
                                                dialog.Respond (Gtk.ResponseType.Cancel);
217
 
                                });
218
 
                        }
219
 
                        base.EndSession ();
220
 
                }
221
 
                
222
 
                protected override void OnResumed ()
223
 
                {
224
 
                        procs = null;
225
 
                        base.OnResumed ();
226
 
                }
227
 
                
228
 
                protected override ProcessInfo[] OnGetProcesses ()
229
 
                {
230
 
                        if (procs == null)
231
 
                                procs = new ProcessInfo[] { new ProcessInfo (0, appName) };
232
 
                        return procs;
233
 
                }
234
 
                
235
 
                protected override void EnsureExited ()
236
 
                {
237
 
                        //no-op, we can't kill remote processes
238
 
                }
239
 
        }
240
 
        
241
 
        public class RemoteDebuggerStartInfo : DebuggerStartInfo
242
 
        {
243
 
                public IPAddress Address { get; private set; }
244
 
                public int DebugPort { get; private set; }
245
 
                public int OutputPort { get; private set; }
246
 
                public bool RedirectOutput { get; private set; }
247
 
                public string AppName { get; set; }
248
 
                public List<AssemblyName> UserAssemblyNames { get; set; }
249
 
                
250
 
                public RemoteDebuggerStartInfo (string appName, IPAddress address, int debugPort)
251
 
                        : this (appName, address, debugPort, false, 0) {}
252
 
                
253
 
                public RemoteDebuggerStartInfo (string appName, IPAddress address, int debugPort, int outputPort)
254
 
                        : this (appName, address, debugPort, outputPort > 0, outputPort) {}
255
 
 
256
 
                RemoteDebuggerStartInfo (string appName, IPAddress address, int debugPort,  bool redirectOutput, int outputPort)
257
 
                {
258
 
                        SoftDebuggerEngine.EnsureSdbLoggingService ();
259
 
                        this.AppName = appName;
260
 
                        this.Address = address;
261
 
                        this.DebugPort = debugPort;
262
 
                        this.OutputPort = outputPort;
263
 
                        this.RedirectOutput = redirectOutput;
264
 
                }
265
 
                
266
 
                internal string LogMessage { get; private set; }
267
 
                
268
 
                public void SetUserAssemblies (IList<string> files)
269
 
                {
270
 
                        string error;
271
 
                        UserAssemblyNames = SoftDebuggerEngine.GetAssemblyNames (files, out error);
272
 
                        LogMessage = error;
273
 
                }
274
 
        }
275
 
}