ConnectionInfo.SendTimeout — configurable socket send timeout to prevent indefinite hangs on TCP zero-window stalls

Abierto
#1,793 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
70/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Tranquilo
Stack tecnológico
csharp
Área
networking

Línea de trabajo

Comienza con ConnectionInfo.cs para revisar la validación de timeout existente y, a continuación, inspecciona la configuración del socket tanto en Connect() como en ConnectAsync() en Session.cs. Añade el comportamiento configurable de send-timeout descrito en el issue, conservando el valor predeterminado infinito, y verifica que un envío bloqueado termina por timeout mientras las conexiones existentes conservan su comportamiento.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Problem

When uploading files over SFTP to a slow or unresponsive server, Session.SendPacket() can hang indefinitely with no way to recover.

The root cause is in SocketAbstraction.Send():

  var bytesSent = socket.Send(data, offset + totalBytesSent, totalBytesToSend - totalBytesSent, SocketFlags.None);

socket.Send() is a blocking call and Socket.SendTimeout is never set, so it defaults to 0 (infinite). When the server's TCP receive window drops to zero (the server is alive but not consuming data), the OS
holds the call open indefinitely — no exception, no return. The standard TCP dead-peer timeout (several minutes) only applies when the server is completely unreachable, not in the zero-window scenario.

This is distinct from the channel-level window wait in Channel.cs, which already has a 30-second timeout via ConnectionInfo.Timeout. That protection only covers the SSH protocol layer; it never gets a chance
to fire because execution is stuck in socket.Send() first.

OperationTimeout (on SftpClient) similarly cannot help — it guards the wait for an SFTP protocol response after a packet has been sent, not the send itself.

Proposed fix

Add SendTimeout to ConnectionInfo (default Timeout.InfiniteTimeSpan to preserve existing behaviour) and apply it to the socket immediately after connection:

  // ConnectionInfo.cs
  private TimeSpan _sendTimeout = System.Threading.Timeout.InfiniteTimeSpan;

  public TimeSpan SendTimeout
  {
      get => _sendTimeout;
      set
      {
          value.EnsureValidTimeout(nameof(SendTimeout));
          _sendTimeout = value;
      }
  }

  // Session.cs — both Connect() and ConnectAsync() paths
  _socket = _serviceFactory.CreateConnector(ConnectionInfo, _socketFactory)
                           .Connect(ConnectionInfo);

  _socket.SendTimeout = ConnectionInfo.SendTimeout.AsTimeout();

When SendTimeout elapses, socket.Send() throws SocketException with SocketError.TimedOut, which propagates out of SendPacket() and terminates the session normally.

Notes

  • Default is infinite — no behaviour change for existing users
  • The timeout is a stall detector, not a total-transfer budget: it resets on every successful send call, so large files over slow-but-healthy connections are not affected
  • Applies to all SSH traffic (not just SFTP), which is correct — a stalled send on any packet type means the session is broken
Lenguaje dominante
C#
Estrellas
4.4k
Forks
993
Merge medio
9 d 21 h
PR fusionados (30 d)
1

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de sshnet/SSH.NET

Todos los issues de sshnet/SSH.NET

Issues similares

Más issues de C#

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.