Description
Current implementation of netshutdown_syscall has several issues:
- shutdown() doesn’t close the file descriptor, even if how is specified as SHUT_RDWR. To close the file descriptor, we must additionally call close(). Our implementation would take the file descriptor if how is SHUT_RDWR, which leads to several other undesired behavior:
- call shutdown with SHUT_RD then SHUT_WR (or reverse) would not behave the same as SHUT_RDWR
- when the file desciptor is taken, all the associated resources havn't been cleaned (NET_METADATA, FS_METADATA)
- Once the socket is fully shutdown (SHUT_RDWR), its local_addr would be set to None, and state will be set back to NOTCONNECTED. This gives an chance to reuse the file descriptor and bind it to a new address, which is not an allowed behavior in Linux.
- Some state are not handled correctly. In Linux, shutdown would behave differently for socket in different state. For example, shutdown with SHUT_RD on socket that is in listen state will disconnect the socket directly, without the need to shutdown it with SHUT_WR again.
- Connection state is not checked, if the socket is not connected, we shall return ENOTCONN error.
- shutdown on AF_UNIX socket is not working. After a SHUT_RD on a UNIX domain stream socket, the peer application receives a SIGPIPE signal and the EPIPE error if it makes further attempts to write to the peer socket; After a SHUT_WR, Once the peer application has read all outstanding data, it will see end-of-file. Subsequent writes to the local socket yield the SIGPIPE signal and an EPIPE error. These behaviors are not matched.
For reference, below is how Linux does for shutdown:
In Linux, socket has two different kinds of state, the first type of state is similar to our ConnState, describing a high level of the state of the socket. However, it does not have state like CONNWRONLY or CONNWRONLY, as shutdown are handled in a competely different way in Linux. Another type of the state is about the current TCP state of the socket (TCP_CLOSE, TCP_SYN_SEND, etc). These two types of state works together to identify current state of the socket. However, shutdown in Linux does not rely on these state actually, the socket struct has a dedicated field called sk_shutdown, which is the place where shutdown state is stored. The sk_shutdown will be checked in send or recv to affect their behavior.