Skip to content

Commit 0289048

Browse files
qianxichen233lindrennergade
authored
test and comments for netshutdown (#313)
* test and comments for netshutdown * fixed minor issue in _cleanup_socket_inner_helper * minor adjustment * resolved some comments * test and comments for netshutdown * fixed minor issue in _cleanup_socket_inner_helper * minor adjustment * resolved some comments --------- Co-authored-by: lind <lind@nyu.edu> Co-authored-by: Nicholas Renner <nicholassrenner@gmail.com>
1 parent d09c658 commit 0289048

File tree

2 files changed

+440
-13
lines changed

2 files changed

+440
-13
lines changed

src/safeposix/syscalls/net_calls.rs

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)