Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writev syscall comments and tests #291

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions src/safeposix/syscalls/fs_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1840,7 +1840,40 @@ impl Cage {
}

//------------------------------------WRITEV SYSCALL------------------------------------

/// ## `writev_syscall`
///
/// ### Description
/// This function writes data to a file descriptor from multiple buffers.
/// Currently, it supports writing to sockets and pipes.
/// The function first retrieves the file descriptor object associated with the provided file descriptor
/// and then matches the file descriptor type and calls the appropriate write function based on the type.
/// * `Sockets`: The function writes data to the connected socket, handling both TCP and UDP sockets.
/// * Checks if the socket is connected (either fully connected or connected for write-only).
/// * If connected, calls the underlying `writev` function on the raw socket.
/// * Handles errors returned by the underlying `writev` function.
/// * `Pipes`: The function writes data to the pipe, supporting non-blocking writes.
/// * Checks if the pipe is open for writing.
/// * Handles non-blocking writes.
/// * Triggers `SIGPIPE` if the pipe is closed on the other end.
///
/// ### Function Arguments
/// * `fd`: The file descriptor to write to.
/// * `iovec`: A pointer to an array of `IovecStruct` objects representing the data buffers to write.
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
/// * `iovcnt`: The number of `IovecStruct` objects in the array.
///
/// ### Returns
/// * The number of bytes written on success.
/// * A negative value on error, with the specific error code set in `errno`.
///
/// ### Errors
/// * `EBADF(9)`: The file descriptor is invalid.
/// * `ENOTCONN(107)`: The socket is not connected (for sockets).
/// * `EOPNOTSUPP(95)`: The system call is not supported for the given socket protocol.
/// * `EAGAIN(11)`: There is no data available right now (for pipes).
/// * `EPIPE(32)`: The pipe has been closed on the other end (for pipes).
/// ### Panics
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
/// * If an unknown error code is returned by the underlying socket writev function.
/// [writev(2)](https://linux.die.net/man/2/writev)
pub fn writev_syscall(
&self,
fd: i32,
Expand All @@ -1855,7 +1888,7 @@ impl Cage {
Socket(socket_filedesc_obj) => {
let sock_tmp = socket_filedesc_obj.handle.clone();
let sockhandle = sock_tmp.write();

// Check the domain of the socket (IPv4 or IPv6)
match sockhandle.domain {
AF_INET | AF_INET6 => match sockhandle.protocol {
IPPROTO_TCP => {
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -1958,6 +1991,7 @@ impl Cage {
}
}
Pipe(pipe_filedesc_obj) => {
// Check if the pipe is open for writing.
if is_rdonly(pipe_filedesc_obj.flags) {
return syscall_error(
Errno::EBADF,
Expand All @@ -1970,7 +2004,7 @@ impl Cage {
if pipe_filedesc_obj.flags & O_NONBLOCK != 0 {
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
nonblocking = true;
}

// Write to the pipe using vectored I/O.
let retval =
pipe_filedesc_obj
.pipe
Expand Down
71 changes: 71 additions & 0 deletions src/tests/fs_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2458,6 +2458,77 @@ pub mod fs_tests {
// Validate the size of the file to be 0 now as should be truncated
assert_eq!(statdata.st_size, 0);

assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
lindrustfinalize();
}
use crate::tests::FileDescriptor::Socket;
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
use std::thread;
#[test]
fn ut_lind_fs_writev_socketpair() {
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);

let mut socketpair = interface::SockPair::default();
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(
Cage::socketpair_syscall(cage.clone(), AF_UNIX, SOCK_STREAM, 0, &mut socketpair),
0
);

let data = b"Hello, world!";
let iovec = interface::IovecStruct {
iov_base: data.as_ptr() as *mut libc::c_void,
iov_len: data.len(),
};

let bytes_written = cage.writev_syscall(socketpair.sock1, &iovec, 1);
assert_eq!(bytes_written, data.len() as i32);

let mut buffer = vec![0u8; data.len()];
let bytes_read = cage.recv_syscall(socketpair.sock2, buffer.as_mut_ptr(), buffer.len(), 0);
assert_eq!(bytes_read, data.len() as i32);

assert_eq!(buffer, data);

assert_eq!(cage.close_syscall(socketpair.sock1), 0);
assert_eq!(cage.close_syscall(socketpair.sock2), 0);

assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
lindrustfinalize();
}

#[test]
fn ut_lind_fs_writev_pipe() {
let _thelock = setup::lock_and_init();
let cage = interface::cagetable_getref(1);

// Create a pipe
let mut pipe_fds = PipeArray::default();
assert_eq!(cage.pipe_syscall(&mut pipe_fds), 0);
let read_fd = pipe_fds.readfd;
let write_fd = pipe_fds.writefd;

// Prepare the data to be written using an iovec structure
rupeshkoushik07 marked this conversation as resolved.
Show resolved Hide resolved
let data = b"Hello, pipe!";
let iovec = interface::IovecStruct {
iov_base: data.as_ptr() as *mut libc::c_void,
iov_len: data.len(),
};

// Write the data to the pipe using writev_syscall
let bytes_written = cage.writev_syscall(write_fd, &iovec, 1);
assert_eq!(bytes_written, data.len() as i32);

// Read the data from the pipe
let mut buffer = vec![0u8; data.len()];
let bytes_read = cage.read_syscall(read_fd, buffer.as_mut_ptr(), buffer.len());
assert_eq!(bytes_read, data.len() as i32);

// Verify that the data read is the same as the data written
assert_eq!(buffer, data);

assert_eq!(cage.close_syscall(read_fd), 0);
assert_eq!(cage.close_syscall(write_fd), 0);

assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
lindrustfinalize();
}
Expand Down