From bb720ad5bb06e02eb6282ab8f6c6e01594dc5141 Mon Sep 17 00:00:00 2001 From: Jacob Roberts Date: Wed, 30 Jul 2025 14:37:30 -0700 Subject: [PATCH 1/3] add event for ssh keep alive --- cs/build/build.props | 2 +- cs/src/Connections/ITunnelClient.cs | 10 +++++++ cs/src/Connections/ITunnelHost.cs | 12 ++++++++- .../SshKeepAliveSuccessEventArgs.cs | 27 +++++++++++++++++++ cs/src/Connections/TunnelClient.cs | 6 ++++- cs/src/Connections/TunnelConnection.cs | 18 +++++++++++++ cs/src/Connections/TunnelRelayTunnelHost.cs | 6 ++++- 7 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 cs/src/Connections/SshKeepAliveSuccessEventArgs.cs diff --git a/cs/build/build.props b/cs/build/build.props index 8585e1d6..8d18c516 100644 --- a/cs/build/build.props +++ b/cs/build/build.props @@ -41,7 +41,7 @@ 5.3.9 4.7.2 15.5.31 - 3.12.8 + 3.12.11 2.4.0 2.4.0 diff --git a/cs/src/Connections/ITunnelClient.cs b/cs/src/Connections/ITunnelClient.cs index 1ad150cd..8cde69b9 100644 --- a/cs/src/Connections/ITunnelClient.cs +++ b/cs/src/Connections/ITunnelClient.cs @@ -203,5 +203,15 @@ Task ConnectAsync( /// if the keep-alive interval is greater than 0. /// public event EventHandler? KeepAliveFailed; + + /// + /// Event raised when a keep-alive message response is received. + /// + /// + /// The event args provide the count of keep-alive messages that got a response within the + /// configured . This callback is only invoked + /// if the keep-alive interval is greater than 0. + /// + public event EventHandler? KeepAliveSucceeded; } diff --git a/cs/src/Connections/ITunnelHost.cs b/cs/src/Connections/ITunnelHost.cs index 7497682a..9de89581 100644 --- a/cs/src/Connections/ITunnelHost.cs +++ b/cs/src/Connections/ITunnelHost.cs @@ -127,7 +127,7 @@ Task ConnectAsync( /// ForwardedPortConnecting event will be raised. /// event EventHandler? ForwardedPortConnecting; - + /// /// Event raised when a keep-alive message response is not received. /// @@ -137,4 +137,14 @@ Task ConnectAsync( /// if the keep-alive interval is greater than 0. /// public event EventHandler? KeepAliveFailed; + + /// + /// Event raised when a keep-alive message response is received. + /// + /// + /// The event args provide the count of keep-alive messages that got a response within the + /// configured . This callback is only invoked + /// if the keep-alive interval is greater than 0. + /// + public event EventHandler? KeepAliveSucceeded; } diff --git a/cs/src/Connections/SshKeepAliveSuccessEventArgs.cs b/cs/src/Connections/SshKeepAliveSuccessEventArgs.cs new file mode 100644 index 00000000..051cec63 --- /dev/null +++ b/cs/src/Connections/SshKeepAliveSuccessEventArgs.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. +// + +using System; + +namespace Microsoft.DevTunnels.Connections; + +/// +/// Event raised when a keep-alive message respose is not received. +/// +public class SshKeepAliveSuccessEventArgs : EventArgs +{ + /// + /// Create a new instance of . + /// + public SshKeepAliveSuccessEventArgs(int count) + { + Count = count; + } + + /// + /// The number of keep-alive messages that have been sent without a response. + /// + public int Count { get; } +} diff --git a/cs/src/Connections/TunnelClient.cs b/cs/src/Connections/TunnelClient.cs index 1b2b5d9a..e8048e5e 100644 --- a/cs/src/Connections/TunnelClient.cs +++ b/cs/src/Connections/TunnelClient.cs @@ -206,10 +206,14 @@ protected async Task StartSshSessionAsync(Stream stream, TunnelConnectionOptions session = new SshClientSession(clientConfig, Trace.WithName("SSH")); SshSession = session; - session.KeepAliveRequestFailed += (_, e) => + session.KeepAliveFailed += (_, e) => { OnKeepAliveFailed(e.Count); }; + session.KeepAliveSucceeded += (_, e) => + { + OnKeepAliveSucceeded(e.Count); + }; SshPortForwardingService = session.ActivateService(); ConfigurePortForwardingService(); SubscribeSessionEvents(session); diff --git a/cs/src/Connections/TunnelConnection.cs b/cs/src/Connections/TunnelConnection.cs index d384f940..c86f3a95 100644 --- a/cs/src/Connections/TunnelConnection.cs +++ b/cs/src/Connections/TunnelConnection.cs @@ -267,6 +267,16 @@ protected virtual void ValidateAccessToken() /// public event EventHandler? KeepAliveFailed; + /// + /// Event raised when a keep-alive message response is received. + /// + /// + /// The event args provide the count of keep-alive messages that got a response within the + /// configured . This callback is only invoked + /// if the keep-alive interval is greater than 0. + /// + public event EventHandler? KeepAliveSucceeded; + /// /// Fetch the tunnel from the service if and are not null. /// @@ -363,6 +373,14 @@ protected virtual void OnKeepAliveFailed(int count) KeepAliveFailed?.Invoke(this, new SshKeepAliveFailureEventArgs(count)); } + /// + /// Event raised when a keep-alive message response is not received. + /// + protected virtual void OnKeepAliveSucceeded(int count) + { + KeepAliveSucceeded?.Invoke(this, new SshKeepAliveSuccessEventArgs(count)); + } + /// public async ValueTask DisposeAsync() { diff --git a/cs/src/Connections/TunnelRelayTunnelHost.cs b/cs/src/Connections/TunnelRelayTunnelHost.cs index 626b6e13..75d008a7 100644 --- a/cs/src/Connections/TunnelRelayTunnelHost.cs +++ b/cs/src/Connections/TunnelRelayTunnelHost.cs @@ -207,10 +207,14 @@ protected override async Task ConfigureSessionAsync(Stream stream, bool isReconn hostPfs.MessageFactory = this; } - session.KeepAliveRequestFailed += (_, e) => + session.KeepAliveFailed += (_, e) => { OnKeepAliveFailed(e.Count); }; + session.KeepAliveSucceeded += (_, e) => + { + OnKeepAliveSucceeded(e.Count); + }; SshSession = session; SubscribeSessionEvents(session); From ce9078b86768a18f46225d8450f5c207f01f5c5d Mon Sep 17 00:00:00 2001 From: Jacob Roberts Date: Thu, 31 Jul 2025 13:11:22 -0700 Subject: [PATCH 2/3] refactor event args to one class --- cs/src/Connections/ITunnelClient.cs | 4 +-- cs/src/Connections/ITunnelHost.cs | 4 +-- ...sEventArgs.cs => SshKeepAliveEventArgs.cs} | 6 ++--- .../SshKeepAliveFailureEventArgs.cs | 27 ------------------- cs/src/Connections/TunnelConnection.cs | 8 +++--- 5 files changed, 11 insertions(+), 38 deletions(-) rename cs/src/Connections/{SshKeepAliveSuccessEventArgs.cs => SshKeepAliveEventArgs.cs} (74%) delete mode 100644 cs/src/Connections/SshKeepAliveFailureEventArgs.cs diff --git a/cs/src/Connections/ITunnelClient.cs b/cs/src/Connections/ITunnelClient.cs index 8cde69b9..e2de7383 100644 --- a/cs/src/Connections/ITunnelClient.cs +++ b/cs/src/Connections/ITunnelClient.cs @@ -202,7 +202,7 @@ Task ConnectAsync( /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveFailed; + public event EventHandler? KeepAliveFailed; /// /// Event raised when a keep-alive message response is received. @@ -212,6 +212,6 @@ Task ConnectAsync( /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveSucceeded; + public event EventHandler? KeepAliveSucceeded; } diff --git a/cs/src/Connections/ITunnelHost.cs b/cs/src/Connections/ITunnelHost.cs index 9de89581..5287607c 100644 --- a/cs/src/Connections/ITunnelHost.cs +++ b/cs/src/Connections/ITunnelHost.cs @@ -136,7 +136,7 @@ Task ConnectAsync( /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveFailed; + public event EventHandler? KeepAliveFailed; /// /// Event raised when a keep-alive message response is received. @@ -146,5 +146,5 @@ Task ConnectAsync( /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveSucceeded; + public event EventHandler? KeepAliveSucceeded; } diff --git a/cs/src/Connections/SshKeepAliveSuccessEventArgs.cs b/cs/src/Connections/SshKeepAliveEventArgs.cs similarity index 74% rename from cs/src/Connections/SshKeepAliveSuccessEventArgs.cs rename to cs/src/Connections/SshKeepAliveEventArgs.cs index 051cec63..d14a443e 100644 --- a/cs/src/Connections/SshKeepAliveSuccessEventArgs.cs +++ b/cs/src/Connections/SshKeepAliveEventArgs.cs @@ -10,12 +10,12 @@ namespace Microsoft.DevTunnels.Connections; /// /// Event raised when a keep-alive message respose is not received. /// -public class SshKeepAliveSuccessEventArgs : EventArgs +public class SshKeepAliveEventArgs : EventArgs { /// - /// Create a new instance of . + /// Create a new instance of . /// - public SshKeepAliveSuccessEventArgs(int count) + public SshKeepAliveEventArgs(int count) { Count = count; } diff --git a/cs/src/Connections/SshKeepAliveFailureEventArgs.cs b/cs/src/Connections/SshKeepAliveFailureEventArgs.cs deleted file mode 100644 index 6bd8db07..00000000 --- a/cs/src/Connections/SshKeepAliveFailureEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. -// - -using System; - -namespace Microsoft.DevTunnels.Connections; - -/// -/// Event raised when a keep-alive message respose is not received. -/// -public class SshKeepAliveFailureEventArgs : EventArgs -{ - /// - /// Create a new instance of . - /// - public SshKeepAliveFailureEventArgs(int count) - { - Count = count; - } - - /// - /// The number of keep-alive messages that have been sent without a response. - /// - public int Count { get; } -} diff --git a/cs/src/Connections/TunnelConnection.cs b/cs/src/Connections/TunnelConnection.cs index c86f3a95..26204e77 100644 --- a/cs/src/Connections/TunnelConnection.cs +++ b/cs/src/Connections/TunnelConnection.cs @@ -265,7 +265,7 @@ protected virtual void ValidateAccessToken() /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveFailed; + public event EventHandler? KeepAliveFailed; /// /// Event raised when a keep-alive message response is received. @@ -275,7 +275,7 @@ protected virtual void ValidateAccessToken() /// configured . This callback is only invoked /// if the keep-alive interval is greater than 0. /// - public event EventHandler? KeepAliveSucceeded; + public event EventHandler? KeepAliveSucceeded; /// /// Fetch the tunnel from the service if and are not null. @@ -370,7 +370,7 @@ protected virtual async Task OnRefreshingTunnelAccessTokenAsync(Cancellati /// protected virtual void OnKeepAliveFailed(int count) { - KeepAliveFailed?.Invoke(this, new SshKeepAliveFailureEventArgs(count)); + KeepAliveFailed?.Invoke(this, new SshKeepAliveEventArgs(count)); } /// @@ -378,7 +378,7 @@ protected virtual void OnKeepAliveFailed(int count) /// protected virtual void OnKeepAliveSucceeded(int count) { - KeepAliveSucceeded?.Invoke(this, new SshKeepAliveSuccessEventArgs(count)); + KeepAliveSucceeded?.Invoke(this, new SshKeepAliveEventArgs(count)); } /// From 0117db72551a07765af15f179dea4b8b40699746 Mon Sep 17 00:00:00 2001 From: Jacob Roberts Date: Thu, 31 Jul 2025 13:20:13 -0700 Subject: [PATCH 3/3] fix comment --- cs/src/Connections/SshKeepAliveEventArgs.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cs/src/Connections/SshKeepAliveEventArgs.cs b/cs/src/Connections/SshKeepAliveEventArgs.cs index d14a443e..436d3cb9 100644 --- a/cs/src/Connections/SshKeepAliveEventArgs.cs +++ b/cs/src/Connections/SshKeepAliveEventArgs.cs @@ -8,7 +8,7 @@ namespace Microsoft.DevTunnels.Connections; /// -/// Event raised when a keep-alive message respose is not received. +/// Event raised when a keep-alive message respose is or is not received. /// public class SshKeepAliveEventArgs : EventArgs { @@ -21,7 +21,7 @@ public SshKeepAliveEventArgs(int count) } /// - /// The number of keep-alive messages that have been sent without a response. + /// The number of keep-alive messages that have been sent with the same state. /// public int Count { get; } }