@@ -2044,13 +2044,53 @@ impl Cage {
20442044 }
20452045 }
20462046
2047+ /// ## ------------------SHUTDOWN SYSCALL------------------
2048+ /// ### Description
2049+ /// The `netshutdown_syscall()` call causes all or part of a full-duplex
2050+ /// connection on the socket associated with fd to be shut down. If "how" is
2051+ /// SHUT_RD, further receptions will be disallowed. If "how" is SHUT_WR,
2052+ /// further transmissions will be disallowed. If "how" is SHUT_RDWR,
2053+ /// further receptions and transmissions will be disallowed.
2054+ ///
2055+ /// ### Function Arguments
2056+ /// The `netshutdown_syscall()` receives two arguments:
2057+ /// * `fd` - The socket file descriptor
2058+ /// * `how` - how to shutdown the socket. If how is SHUT_RD, further
2059+ /// receptions will be disallowed. If how is SHUT_WR, further
2060+ /// transmissions will be disallowed. If how is SHUT_RDWR, further
2061+ /// receptions and transmissions will be disallowed.
2062+ ///
2063+ /// ### Returns
2064+ /// On success, zero is returned. Otherwise, errors or panics are returned
2065+ /// for different scenarios.
2066+ ///
2067+ /// ### Errors
2068+ /// * EBADF - An invalid file descriptor was given in one of the sets
2069+ /// * EINVAL - An invalid value was specified in "how"
2070+ /// * ENOTSOCK - The file descriptor sockfd does not refer to a socket.
2071+ /// * ENOTCONN - The specified socket is not connected.
2072+ ///
2073+ /// ### Panics
2074+ /// No panic is expected from this syscall
20472075 pub fn netshutdown_syscall ( & self , fd : i32 , how : i32 ) -> i32 {
2076+ // BUG: we did not check if the specified socket is connected or not
2077+
2078+ // first let's check fd range
2079+ if fd < 0 || fd >= MAXFD {
2080+ return syscall_error (
2081+ Errno :: EBADF ,
2082+ "netshutdown" ,
2083+ "provided fd is not a valid file descriptor" ,
2084+ ) ;
2085+ }
2086+
20482087 match how {
20492088 SHUT_RDWR | SHUT_RD | SHUT_WR => {
20502089 return Self :: _cleanup_socket ( self , fd, how) ;
20512090 }
20522091 _ => {
2053- //See http://linux.die.net/man/2/shutdown for nuance to this error
2092+ // invalid how argument
2093+ // See http://linux.die.net/man/2/shutdown for nuance to this error
20542094 return syscall_error (
20552095 Errno :: EINVAL ,
20562096 "netshutdown" ,
@@ -2060,47 +2100,67 @@ impl Cage {
20602100 }
20612101 }
20622102
2103+ // this function handles the core logic of shutdown
20632104 pub fn _cleanup_socket_inner_helper (
20642105 sockhandle : & mut SocketHandle ,
20652106 how : i32 ,
20662107 shutdown : bool ,
20672108 ) -> i32 {
20682109 // we need to do a bunch of actual socket cleanup for INET sockets
20692110 if sockhandle. domain != AF_UNIX {
2111+ // this flag is used for marking if we want to release the resources of the
2112+ // socket
20702113 let mut releaseflag = false ;
20712114 if let Some ( ref sobj) = sockhandle. innersocket {
2115+ // get the innersocket
20722116 if shutdown {
2117+ // shutdown the internal socket with libc shutdown
20732118 let shutresult = sobj. shutdown ( how) ;
20742119
20752120 if shutresult < 0 {
2121+ // in case of error from libc shutdown, return the errno
20762122 match Errno :: from_discriminant ( interface:: get_errno ( ) ) {
20772123 Ok ( i) => {
20782124 return syscall_error (
20792125 i,
20802126 "shutdown" ,
2081- "The libc call to setsockopt failed!" ,
2127+ "The libc call to shutdown failed!" ,
20822128 ) ;
20832129 }
2084- Err ( ( ) ) => panic ! ( "Unknown errno value from setsockopt returned!" ) ,
2130+ Err ( ( ) ) => panic ! ( "Unknown errno value from shutdown returned!" ) ,
20852131 } ;
20862132 }
20872133
2134+ // here we want to release the resources (port, innersocket) if the socket is
2135+ // closed on RD and WR at the same time. however, BUG: this
2136+ // is not something that is supposed to be done in shutdown, instead, they
2137+ // should be handled in close
20882138 match how {
20892139 SHUT_RD => {
2140+ // if we shutdown RD on a socket that is already in RDONLY state
2141+ // that would mean the socket can neither read or write
2142+ // so we want to release its resources
20902143 if sockhandle. state == ConnState :: CONNRDONLY {
20912144 releaseflag = true ;
20922145 }
20932146 }
20942147 SHUT_WR => {
2148+ // if we shutdown WR on a socket that is already in WRONLY state
2149+ // that would mean the socket can neither read or write
2150+ // so we want to release its resources
20952151 if sockhandle. state == ConnState :: CONNWRONLY {
20962152 releaseflag = true ;
20972153 }
20982154 }
20992155 SHUT_RDWR => {
2156+ // we shutdown RD and WR
2157+ // that would mean the socket can neither read or write
2158+ // so we want to release its resources
21002159 releaseflag = true ;
21012160 }
21022161 _ => {
2103- //See http://linux.die.net/man/2/shutdown for nuance to this error
2162+ // invalid how argument
2163+ // See http://linux.die.net/man/2/shutdown for nuance to this error
21042164 return syscall_error (
21052165 Errno :: EINVAL ,
21062166 "netshutdown" ,
@@ -2109,51 +2169,69 @@ impl Cage {
21092169 }
21102170 }
21112171 } else {
2112- //Reaching this means that the socket is closed. Removing the sockobj
2113- //indicates that the sockobj will drop, and therefore close
2172+ // Reaching this means that the socket is closed after close_syscall. Removing
2173+ // the sockobj indicates that the sockobj will drop, and therefore close
21142174 releaseflag = true ;
21152175 sockhandle. innersocket = None ;
21162176 }
21172177 }
21182178
2179+ // if we want to release the associated resources of the socket
21192180 if releaseflag {
21202181 if let Some ( localaddr) = sockhandle. localaddr . as_ref ( ) . clone ( ) {
2121- //move to end
2182+ // release the port
21222183 let release_ret_val = NET_METADATA . _release_localport (
21232184 localaddr. addr ( ) ,
21242185 localaddr. port ( ) ,
21252186 sockhandle. protocol ,
21262187 sockhandle. domain ,
21272188 ) ;
2189+ // release the localaddr
21282190 sockhandle. localaddr = None ;
21292191 if let Err ( e) = release_ret_val {
2192+ // in case of any error in releasing the port
2193+ // return the error
21302194 return e;
21312195 }
21322196 }
21332197 }
21342198 }
21352199
2136- // now change the connections for all socket types
2200+ // now change the connection state for all socket types
21372201 match how {
21382202 SHUT_RD => {
2139- if sockhandle. state == ConnState :: CONNWRONLY {
2203+ if sockhandle. state == ConnState :: CONNRDONLY {
2204+ // shutdown RD on socket with RDONLY state means
2205+ // the socket is neither readable nor writable
21402206 sockhandle. state = ConnState :: NOTCONNECTED ;
21412207 } else {
2208+ // otherwise, we only closed RD, and the socket can still write
2209+ // however, BUG: Linux is handling shutdown for different state seperately.
2210+ // shutdown on RD does not mean the socket would always be WRONLY. for example,
2211+ // if the socket is in LISTEN state, shutdown on RD will cause the socket to
2212+ // disconnect directly, without the need to shutdown on WR again.
21422213 sockhandle. state = ConnState :: CONNWRONLY ;
21432214 }
21442215 }
21452216 SHUT_WR => {
2146- if sockhandle. state == ConnState :: CONNRDONLY {
2217+ if sockhandle. state == ConnState :: CONNWRONLY {
2218+ // shutdown WR on socket with WRONLY state means
2219+ // the socket is neither readable nor writable
21472220 sockhandle. state = ConnState :: NOTCONNECTED ;
21482221 } else {
2222+ // otherwise, we only closed WR, and the socket can still read
2223+ // however, see above BUG
21492224 sockhandle. state = ConnState :: CONNRDONLY ;
21502225 }
21512226 }
21522227 SHUT_RDWR => {
2228+ // the socket is neither readable nor writable
2229+ // we just set the state to not connected
21532230 sockhandle. state = ConnState :: NOTCONNECTED ;
21542231 }
21552232 _ => {
2156- //See http://linux.die.net/man/2/shutdown for nuance to this error
2233+ // invalid how argument
2234+ // See http://linux.die.net/man/2/shutdown for nuance to this error
21572235 return syscall_error (
21582236 Errno :: EINVAL ,
21592237 "netshutdown" ,
@@ -2165,18 +2243,21 @@ impl Cage {
21652243 return 0 ;
21662244 }
21672245
2246+ // this function is an inner function of shutdown and checks for fd type
21682247 pub fn _cleanup_socket_inner (
21692248 & self ,
21702249 filedesc : & mut FileDescriptor ,
21712250 how : i32 ,
21722251 shutdown : bool ,
21732252 ) -> i32 {
21742253 if let Socket ( sockfdobj) = filedesc {
2254+ // get write lock of sockhandle
21752255 let sock_tmp = sockfdobj. handle . clone ( ) ;
21762256 let mut sockhandle = sock_tmp. write ( ) ;
21772257
21782258 Self :: _cleanup_socket_inner_helper ( & mut * sockhandle, how, shutdown)
21792259 } else {
2260+ // this file descriptor is not a socket fd
21802261 syscall_error (
21812262 Errno :: ENOTSOCK ,
21822263 "cleanup socket" ,
@@ -2185,19 +2266,27 @@ impl Cage {
21852266 }
21862267 }
21872268
2269+ // this function is an inner function of shutdown and checks for fd
21882270 pub fn _cleanup_socket ( & self , fd : i32 , how : i32 ) -> i32 {
2271+ // get the file descriptor object
21892272 let checkedfd = self . get_filedescriptor ( fd) . unwrap ( ) ;
21902273 let mut unlocked_fd = checkedfd. write ( ) ;
21912274 if let Some ( ref mut filedesc_enum) = & mut * unlocked_fd {
21922275 let inner_result = self . _cleanup_socket_inner ( filedesc_enum, how, true ) ;
21932276 if inner_result < 0 {
2277+ // in case of error, return the error
21942278 return inner_result;
21952279 }
21962280
2281+ // if how is SHUT_RDWR, we clear this file descriptor
2282+ // however, BUG: according to standard, shutdown() doesn’t close the file
2283+ // descriptor, even if how is specified as SHUT_RDWR. To close the file
2284+ // descriptor, we must additionally call close().
21972285 if how == SHUT_RDWR {
21982286 let _discarded_fd = unlocked_fd. take ( ) ;
21992287 }
22002288 } else {
2289+ // file descriptor does not exist
22012290 return syscall_error ( Errno :: EBADF , "cleanup socket" , "invalid file descriptor" ) ;
22022291 }
22032292
0 commit comments