Esempio n. 1
0
        /// <summary>
        /// Connects to and performs the initial handshake with the remote debugging server, verifying protocol signature and version number,
        /// and returns the opened stream in a state ready to receive further ptvsd commands (e.g. attach).
        /// </summary>
        public static async Task <DebugConnection> ConnectAsync(Uri uri, bool warnAboutAuthenticationErrors, CancellationToken ct)
        {
            var transport = DebuggerTransportFactory.Get(uri);

            if (transport == null)
            {
                throw new ConnectionException(ConnErrorMessages.RemoteInvalidUri);
            }

            Stream stream = null;

            do
            {
                try {
                    stream = transport.Connect(uri, warnAboutAuthenticationErrors);
                } catch (AuthenticationException ex) {
                    if (!warnAboutAuthenticationErrors)
                    {
                        // This should never happen, but if it does, we don't want to keep trying.
                        throw new ConnectionException(ConnErrorMessages.RemoteSslError, ex);
                    }

                    string errText = Strings.RemoteProcessAuthenticationErrorWarning.FormatUI(ex.Message);
                    var    dlgRes  = MessageBox.Show(errText, Strings.ProductTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                    if (dlgRes == DialogResult.Yes)
                    {
                        warnAboutAuthenticationErrors = false;
                    }
                    else
                    {
                        throw new ConnectionException(ConnErrorMessages.RemoteSslError, ex);
                    }
                }
            } while (stream == null);

            var  debugConn = new DebugConnection(stream);
            bool connected = false;

            try {
                string serverDebuggerName            = string.Empty;
                int    serverDebuggerProtocolVersion = 0;
                using (var connectedEvent = new AutoResetEvent(false)) {
                    EventHandler <LDP.RemoteConnectedEvent> eventReceived = (object sender, LDP.RemoteConnectedEvent ea) => {
                        serverDebuggerName            = ea.debuggerName;
                        serverDebuggerProtocolVersion = ea.debuggerProtocolVersion;
                        try {
                            connectedEvent.Set();
                        } catch (ObjectDisposedException) {
                        }
                        debugConn.Authenticated();
                    };

                    // When the server accepts a connection, it sends an event and then waits for a request
                    debugConn.LegacyRemoteConnected += eventReceived;
                    try {
                        debugConn.StartListening();
                        bool received = connectedEvent.WaitOne(ConnectTimeoutMs);
                        if (!received)
                        {
                            throw new ConnectionException(ConnErrorMessages.TimeOut);
                        }
                    } finally {
                        debugConn.LegacyRemoteConnected -= eventReceived;
                    }
                }

                if (serverDebuggerName != DebuggerSignature)
                {
                    throw new ConnectionException(ConnErrorMessages.RemoteUnsupportedServer);
                }

                // If we are talking the same protocol but different version, reply with signature + version before bailing out
                // so that ptvsd has a chance to gracefully close the socket on its side.
                var response = await debugConn.SendRequestAsync(new LDP.RemoteDebuggerAuthenticateRequest()
                {
                    clientSecret            = uri.UserInfo,
                    debuggerName            = DebuggerSignature,
                    debuggerProtocolVersion = DebuggerProtocolVersion,
                }, ct);

                if (serverDebuggerProtocolVersion != DebuggerProtocolVersion)
                {
                    throw new ConnectionException(ConnErrorMessages.RemoteUnsupportedServer);
                }

                if (!response.accepted)
                {
                    throw new ConnectionException(ConnErrorMessages.RemoteSecretMismatch);
                }

                connected = true;
                return(debugConn);
            } catch (IOException ex) {
                throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex);
            } catch (SocketException ex) {
                throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex);
            } finally {
                if (!connected)
                {
                    debugConn?.Dispose();
                }
            }
        }
Esempio n. 2
0
        public static async Task <PythonRemoteDebugProcess> ConnectAsync(PythonRemoteDebugPort port, TextWriter debugLog, CancellationToken ct)
        {
            PythonRemoteDebugProcess process = null;

            // Connect to the remote debugging server and obtain process information. If any errors occur, display an error dialog, and keep
            // trying for as long as user clicks "Retry".
            while (true)
            {
                DebugConnection     debugConn = null;
                ConnectionException connEx    = null;
                try {
                    // Process information is not sensitive, so ignore any SSL certificate errors, rather than bugging the user with warning dialogs.
                    debugConn = await PythonRemoteProcess.ConnectAsync(port.Uri, false, debugLog, ct);
                } catch (ConnectionException ex) {
                    connEx = ex;
                }

                using (debugConn) {
                    if (debugConn != null)
                    {
                        try {
                            var response = await debugConn.SendRequestAsync(new LDP.RemoteDebuggerInfoRequest(), ct);

                            process = new PythonRemoteDebugProcess(port, response.processId, response.executable, response.user, response.pythonVersion);
                            break;
                        } catch (IOException ex) {
                            connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex);
                        } catch (FailedRequestException ex) {
                            connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex);
                        }
                    }

                    if (connEx != null)
                    {
                        string errText;
                        switch (connEx.Error)
                        {
                        case ConnErrorMessages.RemoteUnsupportedServer:
                            errText = Strings.RemoteUnsupportedServer_Host.FormatUI(port.Uri);
                            break;

                        case ConnErrorMessages.RemoteSecretMismatch:
                            errText = Strings.RemoteSecretMismatch_Host.FormatUI(new UriBuilder(port.Uri)
                            {
                                UserName = null, Password = null
                            }.Uri);
                            break;

                        case ConnErrorMessages.RemoteSslError:
                            // User has already got a warning dialog and clicked "Cancel" on that, so no further prompts are needed.
                            return(null);

                        default:
                        {
                            // Azure uses HTTP 503 (Service Unavailable) to indicate that websocket connections are not supported. Show a special error message for that.
                            var wsEx = connEx.InnerException as WebSocketException;
                            if (wsEx != null)
                            {
                                var webEx = wsEx.InnerException as WebException;
                                if (webEx != null)
                                {
                                    var httpResponse = webEx.Response as HttpWebResponse;
                                    if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.ServiceUnavailable)
                                    {
                                        errText = Strings.RemoteAzureServiceUnavailable_Host.FormatUI(port.Uri);
                                        break;
                                    }
                                }
                            }

                            errText = Strings.RemoteServiceUnavailable_Host.FormatUI(port.Uri);
                            for (var ex = connEx.InnerException; ex != null; ex = ex.InnerException)
                            {
                                if (ex.InnerException == null)
                                {
                                    errText += "\r\n\r\n{0}\r\n{1}".FormatUI(Strings.AdditionalInformation, ex.Message);
                                }
                            }
                            break;
                        }
                        }

                        DialogResult dlgRes = MessageBox.Show(errText, Strings.ProductTitle, MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
                        if (dlgRes != DialogResult.Retry)
                        {
                            break;
                        }
                    }
                }
            }

            return(process);
        }