Skip to content

Commit 3ecae1d

Browse files
qianxichen233lind
andauthored
added more tests for socketpair syscall and fixed an issue with prior socketpair test (#256)
* resolve conflict * restructured socketpair test * fixed net_tests & fixed typo * switch to panic hook in test * added comments for socketpair * updated socketpair_syscall comments * updated comments for socketpair * resolved conflict * resolved comments * resolved comments --------- Co-authored-by: lind <lind@nyu.edu>
1 parent 481a4fb commit 3ecae1d

File tree

3 files changed

+329
-16
lines changed

3 files changed

+329
-16
lines changed

src/safeposix/syscalls/net_calls.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3194,6 +3194,56 @@ impl Cage {
31943194
}
31953195
}
31963196

3197+
/// ## ------------------SOCKETPAIR SYSCALL------------------
3198+
/// ### Description
3199+
/// The `socketpair_syscall()` call creates an unnamed pair of connected
3200+
/// sockets in the specified domain, of the specified type, and using
3201+
/// the optionally specified protocol.
3202+
/// The file descriptors used in referencing the new sockets are returned
3203+
/// in sv.sock1 and sv.sock2. The two sockets are indistinguishable.
3204+
/// ### Function Arguments
3205+
/// The `socketpair_syscall()` receives four arguments:
3206+
/// * `domain` - The domain argument specifies a communication domain; this
3207+
/// selects the protocol family which will be used for communication.
3208+
/// Currently supported domains are AF_UNIX, AF_INET and AF_INET6.
3209+
/// * `socktype` - specifies the communication semantics. Currently defined
3210+
/// types are:
3211+
/// 1. SOCK_STREAM Provides sequenced, reliable, two-way,
3212+
/// connection-based byte streams. An out-of-band data
3213+
/// transmission mechanism may be supported.
3214+
/// 2. SOCK_DGRAM Supports datagrams (connectionless,
3215+
/// unreliable messages of a fixed maximum length). The
3216+
/// type argument serves a second purpose: in addition to
3217+
/// specifying a socket type, it may include the bitwise
3218+
/// OR of any of the following values, to modify the
3219+
/// behavior of the socket:
3220+
/// 1. SOCK_NONBLOCK Set the O_NONBLOCK file status flag on
3221+
/// the open file description referred to by the new file
3222+
/// descriptor.
3223+
/// 2. SOCK_CLOEXEC Set the close-on-exec flag on the new
3224+
/// file descriptor.
3225+
/// * `protocol` - The protocol specifies a particular protocol to be used
3226+
/// with the socket. Currently only support the default protocol
3227+
/// (IPPROTO_TCP).
3228+
/// * `sv` - The file descriptors used in referencing the new sockets are
3229+
/// returned in sv.sock1 and sv.sock2. The two sockets are
3230+
/// indistinguishable.
3231+
3232+
/// ### Returns
3233+
/// On success, zero is returned. Otherwise, errors or panics are returned
3234+
/// for different scenarios.
3235+
///
3236+
/// ### Errors
3237+
/// * EAFNOSUPPORT - The specified address family is not supported on this
3238+
/// machine.
3239+
/// * EOPNOTSUPP - The specified protocol does not support creation of
3240+
/// socket pairs.
3241+
/// * EINVAL - The specified flag is not valid
3242+
/// * ENFILE - no enough file descriptors can be assigned
3243+
///
3244+
/// ### Panics
3245+
/// No Panic is expected for this syscall.
3246+
31973247
// Because socketpair needs to spawn off a helper thread to connect the two ends
31983248
// of the socket pair, and because that helper thread, along with the main
31993249
// thread, need to access the cage to call methods (syscalls) of it, and because
@@ -3208,14 +3258,22 @@ impl Cage {
32083258
protocol: i32,
32093259
sv: &mut interface::SockPair,
32103260
) -> i32 {
3211-
let newprotocol = if protocol == 0 { IPPROTO_TCP } else { protocol };
3261+
let newprotocol = if protocol == 0 { IPPROTO_TCP } else { protocol }; // only support protocol of 0 currently
3262+
// BUG: current implementation of socketpair creates two sockets and bind to an
3263+
// unique address.
3264+
// But according to standard, the sockets created from socketpair should not
3265+
// bind to any address
3266+
32123267
// firstly check the parameters
3268+
// socketpair should always be a AF_UNIX TCP socket
32133269
if domain != AF_UNIX {
32143270
return syscall_error(
32153271
Errno::EOPNOTSUPP,
32163272
"socketpair",
32173273
"Linux socketpair only supports AF_UNIX aka AF_LOCAL domain.",
32183274
);
3275+
// socket type is stored at the lowest 3 bits
3276+
// so we and it with 0x7 to retrieve it
32193277
} else if socktype & 0x7 != SOCK_STREAM || newprotocol != IPPROTO_TCP {
32203278
return syscall_error(
32213279
Errno::EOPNOTSUPP,
@@ -3224,6 +3282,12 @@ impl Cage {
32243282
);
32253283
}
32263284

3285+
// check if socktype contains any invalid flag bits
3286+
if socktype & !(SOCK_NONBLOCK | SOCK_CLOEXEC | 0x7) != 0 {
3287+
return syscall_error(Errno::EINVAL, "socket", "Invalid combination of flags");
3288+
}
3289+
3290+
// get the flags
32273291
let nonblocking = (socktype & SOCK_NONBLOCK) != 0;
32283292
let cloexec = (socktype & SOCK_CLOEXEC) != 0;
32293293

@@ -3248,6 +3312,7 @@ impl Cage {
32483312
let sock2fd = this._socket_inserter(Socket(sock2fdobj.clone()));
32493313

32503314
// assign local addresses and connect
3315+
// we are not supposed to assign and bind address to socketpair sockets
32513316
let sock1tmp = sock1fdobj.handle.clone();
32523317
let sock2tmp = sock2fdobj.handle.clone();
32533318
let mut sock1handle = sock1tmp.write();
@@ -3275,6 +3340,9 @@ impl Cage {
32753340
sv.sock1 = sock1fd;
32763341
sv.sock2 = sock2fd;
32773342

3343+
// since socket file should not exist in the first place
3344+
// the code below is supposed to be removed as well
3345+
32783346
// we need to increment the refcount of the sockets we created
32793347
// reason: in bind_inner_socket, we added entries to the inode table
32803348
let inode1num = sock1handle.unix_info.as_mut().unwrap().inode;

src/tests/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ mod setup {
3333

3434
// Using explicit lifetime to have a safe reference to the lock in the tests.
3535
pub fn lock_and_init<'a>() -> std::sync::MutexGuard<'a, bool> {
36+
set_panic_hook();
37+
3638
//acquiring a lock on TESTMUTEX prevents other tests from running concurrently
3739
let thelock = TESTMUTEX.lock().unwrap();
38-
40+
3941
interface::RUSTPOSIX_TESTSUITE.store(true, interface::RustAtomicOrdering::Relaxed);
4042

4143
//setup the lind filesystem, creates a clean filesystem for each test
@@ -87,6 +89,18 @@ mod setup {
8789
//return the lock to the caller which holds it till the end of the test.
8890
thelock
8991
}
92+
93+
fn set_panic_hook() {
94+
let orig_hook = std::panic::take_hook();
95+
std::panic::set_hook(Box::new(move |panic_info| {
96+
// this hook would be triggered whenever a panic occurs
97+
// good for test cases that panicked inside the non-main thread
98+
// so the trace information could be printed immediately
99+
// instead of raising the error when the thread is joined, which might
100+
// never happen and left the test blocking forever in some test cases
101+
orig_hook(panic_info);
102+
}));
103+
}
90104
}
91105

92106
pub fn str2cbuf(ruststr: &str) -> *mut u8 {

0 commit comments

Comments
 (0)