fix(dialer): evict dead SSHD sessions before reuse to prevent channel-open failure (#382)
When an SSH session behind an SSHD dialer dies silently (NAT timeout, server disconnect, idle TCP drop), IsClosed() may still return false because the health-check goroutine hasn't detected the failure yet. Returning this dead cached session to the connector causes: ssh: unexpected packet in response to channel open: Add a Ping(req)-based liveness check before returning a cached session. If the ping fails, evict the session so the next Dial rebuilds a fresh connection. This matches the dead-session eviction pattern already used by the SSH, KCP, QUIC, and ICMP dialers. Also export the ping-as-health-check as Session.Ping(timeout) so it can be used by external health probes. Retain the existing ping() helper unmodified.
This commit is contained in:
@@ -114,6 +114,25 @@ func (s *Session) Keepalive(interval, timeout time.Duration, retries int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Ping checks if the SSH session is alive by sending a keepalive request.
|
||||
// It blocks until a response is received or the timeout expires.
|
||||
// A nil error indicates the session is healthy.
|
||||
func (s *Session) Ping(timeout time.Duration) error {
|
||||
if timeout <= 0 {
|
||||
timeout = defaultKeepaliveTimeout
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
select {
|
||||
case err := <-s.ping():
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) ping() <-chan error {
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user