Skip to content
  • anonymouspage's avatar
    69f23482
    Use shutdown() ahead of close() for rlogin/ssh · 69f23482
    anonymouspage authored
    Using only close() on a socket has a few issues:
    
     (1) poll is not required to wake on such events leading to hangs
         if infinite timeouts are used.
    
         This can be observed in macOS:
    
         (a) syncterm -iC
         (b) connect via telnet to some system
         (c) use the menu to disconnect from the system
    
         Note: socket must be idle to reproduce.
    
     (2) If a blocked recv/send receives an error in response to a close
         from another thread, the context of the socket has been lost: the
         descriptor is free to be reallocated under the thread performing
         I/O by the system. Any retry logic that may be written in response
         to the error condition could lead to operations being performed
         on a valid but incorrect resource.
    
     (3) Processes that inherited the socket via fork() will still have
         a valid descriptor to the socket. i.e., the socket does not
         globally shutdown via a call to close(); however, shutdown()
         acts on the connection by triggering a TCP FIN. This will lead
         to the actual shutdown of the socket by the remote connection
         as well.
    
    Solution:
    
    Use shutdown() ahead of close(). This will initiate a proper shutdown
    sequence on the socket while leaving the descriptor open. poll() will
    wake, and a subsequent read or write will yield the desired EOF/EPIPE.
    69f23482
    Use shutdown() ahead of close() for rlogin/ssh
    anonymouspage authored
    Using only close() on a socket has a few issues:
    
     (1) poll is not required to wake on such events leading to hangs
         if infinite timeouts are used.
    
         This can be observed in macOS:
    
         (a) syncterm -iC
         (b) connect via telnet to some system
         (c) use the menu to disconnect from the system
    
         Note: socket must be idle to reproduce.
    
     (2) If a blocked recv/send receives an error in response to a close
         from another thread, the context of the socket has been lost: the
         descriptor is free to be reallocated under the thread performing
         I/O by the system. Any retry logic that may be written in response
         to the error condition could lead to operations being performed
         on a valid but incorrect resource.
    
     (3) Processes that inherited the socket via fork() will still have
         a valid descriptor to the socket. i.e., the socket does not
         globally shutdown via a call to close(); however, shutdown()
         acts on the connection by triggering a TCP FIN. This will lead
         to the actual shutdown of the socket by the remote connection
         as well.
    
    Solution:
    
    Use shutdown() ahead of close(). This will initiate a proper shutdown
    sequence on the socket while leaving the descriptor open. poll() will
    wake, and a subsequent read or write will yield the desired EOF/EPIPE.
Loading