// Qualifier for our transport has one of the following formats: // // tcp[s]://[secret@]hostname[:port] // ws[s]://[secret@]hostname[:port][/path] // [secret@]hostname[:port] // // 'tcp' and 'tcps' are for connecting directly to ptvsd; 'ws' and 'wss' are for connecting through WebSocketProxy. // The versions ending with '...s' use SSL to secure the connection. If no scheme is specified, 'tcp' is the default. // If port is not specified, it defaults to 5678 for 'tcp' and 'tcps', 80 for 'ws' and 443 for 'wss'. public int AddPort(IDebugPortRequest2 pRequest, out IDebugPort2 ppPort) { ppPort = null; string name; pRequest.GetPortName(out name); // Support old-style 'hostname:port' format, as well. if (!name.Contains("://")) { name = "tcp://" + name; } var uri = new Uri(name, UriKind.Absolute); var transport = DebuggerTransportFactory.Get(uri); if (transport == null) { MessageBox.Show( Strings.RemoteUnrecognizedDebuggingTransport.FormatUI(uri.Scheme), Strings.ProductTitle, MessageBoxButtons.OK, MessageBoxIcon.Error ); return(VSConstants.E_FAIL); } var validationError = transport.Validate(uri); if (validationError != null) { return(validationError.HResult); } var port = new PythonRemoteDebugPort(this, pRequest, uri, DebugLog); if (PythonDebugOptionsServiceHelper.Options.UseLegacyDebugger) { // Validate connection early. Debugger automation (DTE) objects are not consistent in error checking from this // point on, so errors reported from EnumProcesses and further calls may be ignored and treated as successes // (with empty result). Reporting an error here works around that. int hr = port.EnumProcesses(out IEnumDebugProcesses2 processes); if (hr < 0) { return(hr); } } ppPort = port; _ports.Add(port); return(VSConstants.S_OK); }
// Qualifier for our transport has one of the following formats: // // tcp[s]://[secret@]hostname[:port] // ws[s]://[secret@]hostname[:port][/path] // [secret@]hostname[:port] // // 'tcp' and 'tcps' are for connecting directly to ptvsd; 'ws' and 'wss' are for connecting through WebSocketProxy. // The versions ending with '...s' use SSL to secure the connection. If no scheme is specified, 'tcp' is the default. // If port is not specified, it defaults to 5678 for 'tcp' and 'tcps', 80 for 'ws' and 443 for 'wss'. public int AddPort(IDebugPortRequest2 pRequest, out IDebugPort2 ppPort) { ppPort = null; string name; pRequest.GetPortName(out name); // Support old-style 'hostname:port' format, as well. if (!name.Contains("://")) { name = "tcp://" + name; } var uri = new Uri(name, UriKind.Absolute); var transport = DebuggerTransportFactory.Get(uri); if (transport == null) { MessageBox.Show( Strings.RemoteUnrecognizedDebuggingTransport.FormatUI(uri.Scheme), Strings.ProductTitle, MessageBoxButtons.OK, MessageBoxIcon.Error ); return(VSConstants.E_FAIL); } var validationError = transport.Validate(uri); if (validationError != null) { return(validationError.HResult); } var port = new PythonRemoteDebugPort(this, pRequest, uri, DebugLog); ppPort = port; _ports.Add(port); return(VSConstants.S_OK); }
/// <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(); } } }
/// <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 Stream Connect(Uri uri, bool warnAboutAuthenticationErrors) { 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 = ex.Message + "\nConnect anyway?"; var dlgRes = MessageBox.Show(errText, null, MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (dlgRes == DialogResult.Yes) { warnAboutAuthenticationErrors = false; } else { throw new ConnectionException(ConnErrorMessages.RemoteSslError, ex); } } } while (stream == null); bool connected = false; try { string sig = stream.ReadAsciiString(DebuggerSignature.Length); if (sig != DebuggerSignature) { throw new ConnectionException(ConnErrorMessages.RemoteUnsupportedServer); } long ver = stream.ReadInt64(); // 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. stream.Write(DebuggerSignatureBytes); stream.WriteInt64(DebuggerProtocolVersion); if (ver != DebuggerProtocolVersion) { throw new ConnectionException(ConnErrorMessages.RemoteUnsupportedServer); } stream.WriteString(uri.UserInfo); string secretResp = stream.ReadAsciiString(Accepted.Length); if (secretResp != Accepted) { throw new ConnectionException(ConnErrorMessages.RemoteSecretMismatch); } connected = true; return(stream); } catch (IOException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } catch (SocketException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } finally { if (!connected) { if (stream != null) { stream.Close(); } } } }