Add support for ioctl FIONREAD, FIOCLEX, FIONCLEX for pipe and uds file
This commit is contained in:
parent
7542a74ebb
commit
883f7b259f
@ -422,6 +422,12 @@ impl<I> Consumer<I> {
|
|||||||
let rb_consumer = self.inner.lock().unwrap();
|
let rb_consumer = self.inner.lock().unwrap();
|
||||||
rb_consumer.capacity()
|
rb_consumer.capacity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the length of data stored in the buffer
|
||||||
|
pub fn ready_len(&self) -> usize {
|
||||||
|
let rb_consumer = self.inner.lock().unwrap();
|
||||||
|
rb_consumer.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Copy> Consumer<I> {
|
impl<I: Copy> Consumer<I> {
|
||||||
|
@ -42,6 +42,10 @@ impl_ioctl_nums_and_cmds! {
|
|||||||
TIOCNOTTY => (0x5422, ()),
|
TIOCNOTTY => (0x5422, ()),
|
||||||
// Get the number of bytes in the input buffer
|
// Get the number of bytes in the input buffer
|
||||||
FIONREAD => (0x541B, mut i32),
|
FIONREAD => (0x541B, mut i32),
|
||||||
|
// Don't close on exec
|
||||||
|
FIONCLEX => (0x5450, ()),
|
||||||
|
// Set close on exec
|
||||||
|
FIOCLEX => (0x5451, ()),
|
||||||
// Low-level access to Linux network devices on man7/netdevice.7
|
// Low-level access to Linux network devices on man7/netdevice.7
|
||||||
// Only non-privileged operations are supported for now
|
// Only non-privileged operations are supported for now
|
||||||
SIOCGIFNAME => (0x8910, mut IfReq),
|
SIOCGIFNAME => (0x8910, mut IfReq),
|
||||||
@ -94,8 +98,21 @@ impl<'a> IoctlCmd<'a> {
|
|||||||
|
|
||||||
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<i32> {
|
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
debug!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
|
debug!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
|
||||||
let file_ref = current!().file(fd)?;
|
let current = current!();
|
||||||
file_ref.ioctl(cmd)
|
let file_ref = current.file(fd)?;
|
||||||
|
let mut file_table = current.files().lock().unwrap();
|
||||||
|
let mut entry = file_table.get_entry_mut(fd)?;
|
||||||
|
match cmd {
|
||||||
|
IoctlCmd::FIONCLEX(_) => {
|
||||||
|
entry.set_close_on_spawn(false);
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
IoctlCmd::FIOCLEX(_) => {
|
||||||
|
entry.set_close_on_spawn(true);
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
_ => return file_ref.ioctl(cmd),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -108,7 +108,23 @@ impl File for PipeReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
ioctl_inner(cmd)
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
IoctlCmd::FIONREAD(arg) => {
|
||||||
|
let ready_len = self.get_ready_len().min(std::i32::MAX as usize) as i32;
|
||||||
|
**arg = ready_len;
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
_ => return_errno!(ENOSYS, "not supported"),
|
||||||
|
};
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipeReader {
|
||||||
|
fn get_ready_len(&self) -> usize {
|
||||||
|
self.consumer.ready_len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +210,12 @@ impl File for PipeWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
ioctl_inner(cmd)
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
_ => return_errno!(ENOSYS, "not supported"),
|
||||||
|
};
|
||||||
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,12 +269,3 @@ impl PipeType for FileRef {
|
|||||||
.ok_or_else(|| errno!(EBADF, "not a pipe writer"))
|
.ok_or_else(|| errno!(EBADF, "not a pipe writer"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl_inner(cmd: &mut IoctlCmd) -> Result<i32> {
|
|
||||||
match cmd {
|
|
||||||
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
|
||||||
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
|
||||||
_ => return_errno!(ENOSYS, "not supported"),
|
|
||||||
};
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
@ -55,16 +55,21 @@ impl File for Stream {
|
|||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
match cmd {
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
||||||
|
IoctlCmd::FIONBIO(nonblocking) => {
|
||||||
|
self.set_nonblocking(**nonblocking != 0);
|
||||||
|
}
|
||||||
IoctlCmd::FIONREAD(arg) => match &*self.inner() {
|
IoctlCmd::FIONREAD(arg) => match &*self.inner() {
|
||||||
Status::Connected(endpoint) => {
|
Status::Connected(endpoint) => {
|
||||||
let bytes_to_read = endpoint.bytes_to_read().min(std::i32::MAX as usize) as i32;
|
let bytes_to_read = endpoint.bytes_to_read().min(std::i32::MAX as usize) as i32;
|
||||||
**arg = bytes_to_read;
|
**arg = bytes_to_read;
|
||||||
Ok(0)
|
|
||||||
}
|
}
|
||||||
_ => return_errno!(ENOTCONN, "unconnected socket"),
|
_ => return_errno!(ENOTCONN, "unconnected socket"),
|
||||||
},
|
},
|
||||||
_ => return_errno!(EINVAL, "unknown ioctl cmd for unix socket"),
|
_ => return_errno!(EINVAL, "unknown ioctl cmd for unix socket"),
|
||||||
}
|
}
|
||||||
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <sgx_report.h>
|
#include <sgx_report.h>
|
||||||
#include <sgx_quote.h>
|
#include <sgx_quote.h>
|
||||||
#ifndef OCCLUM_DISABLE_DCAP
|
#ifndef OCCLUM_DISABLE_DCAP
|
||||||
@ -487,21 +490,78 @@ int test_ioctl_SIOCGIFCONF(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int test_ioctl_FIONBIO(void) {
|
int test_ioctl_FIONBIO(void) {
|
||||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
int test_sock[2], sock;
|
||||||
|
test_sock[0] = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
test_sock[1] = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
sock = test_sock[i];
|
||||||
|
int on = 1;
|
||||||
|
if (ioctl(sock, FIONBIO, &on) < 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("ioctl FIONBIO failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
int actual_flags = fcntl(sock, F_GETFL);
|
||||||
|
if ((actual_flags & O_NONBLOCK) == 0) {
|
||||||
|
close(sock);
|
||||||
|
THROW_ERROR("failed to check the O_NONBLOCK flag after FIONBIO");
|
||||||
|
}
|
||||||
|
|
||||||
int on = 1;
|
|
||||||
if (ioctl(sock, FIONBIO, &on) < 0) {
|
|
||||||
close(sock);
|
close(sock);
|
||||||
THROW_ERROR("ioctl FIONBIO failed");
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_ioctl_FIOCLEX(void) {
|
||||||
|
// Open a file with O_CLOEXEC (close-on-exec)
|
||||||
|
char *tmp_file = "/tmp/test_fioclex";
|
||||||
|
int fd = open(tmp_file, O_CREAT | O_CLOEXEC, 0666);
|
||||||
|
if (fd < 0) {
|
||||||
|
THROW_ERROR("failed to open the tmp file");
|
||||||
}
|
}
|
||||||
|
|
||||||
int actual_flags = fcntl(sock, F_GETFL);
|
// change this fd to "no close-on-exec"
|
||||||
if ((actual_flags & O_NONBLOCK) == 0) {
|
int ret = ioctl(fd, FIONCLEX, NULL);
|
||||||
close(sock);
|
if (ret != 0) {
|
||||||
THROW_ERROR("failed to check the O_NONBLOCK flag after FIONBIO");
|
THROW_ERROR("ioctl FIONCLEX failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock);
|
int pipefds[2];
|
||||||
|
ret = pipe(pipefds);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to create pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set close on exec on reader end
|
||||||
|
ret = ioctl(pipefds[0], FIOCLEX, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("ioctl FIOCLEX failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct child process args
|
||||||
|
int child_pid, status;
|
||||||
|
int child_argc =
|
||||||
|
6; // ./nauty_child -t fioclex regular_file_fd pipe_reader_fd pipe_writer_fd
|
||||||
|
char **child_argv = calloc(1, sizeof(char *) * (child_argc + 1));
|
||||||
|
child_argv[0] = strdup("naughty_child");
|
||||||
|
child_argv[1] = strdup("-t");
|
||||||
|
child_argv[2] = strdup("fioclex");
|
||||||
|
asprintf(&child_argv[3], "%d", fd);
|
||||||
|
asprintf(&child_argv[4], "%d", pipefds[0]);
|
||||||
|
asprintf(&child_argv[5], "%d", pipefds[1]);
|
||||||
|
|
||||||
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, NULL, child_argv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = waitpid(child_pid, &status, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
printf("child process %d exit status = %d\n", child_pid, status);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,6 +582,7 @@ static test_case_t test_cases[] = {
|
|||||||
#endif
|
#endif
|
||||||
TEST_CASE(test_ioctl_SIOCGIFCONF),
|
TEST_CASE(test_ioctl_SIOCGIFCONF),
|
||||||
TEST_CASE(test_ioctl_FIONBIO),
|
TEST_CASE(test_ioctl_FIONBIO),
|
||||||
|
TEST_CASE(test_ioctl_FIOCLEX),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <features.h>
|
#include <features.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
char **g_argv;
|
||||||
|
|
||||||
void sigio_handler(int sig) {
|
void sigio_handler(int sig) {
|
||||||
printf("[child] SIGIO is caught in child!\n");
|
printf("[child] SIGIO is caught in child!\n");
|
||||||
}
|
}
|
||||||
@ -70,6 +73,33 @@ int test_spawn_attribute_sigdef() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_ioctl_fioclex() {
|
||||||
|
int regular_file_fd = atoi(g_argv[3]);
|
||||||
|
int pipe_reader_fd = atoi(g_argv[4]);
|
||||||
|
int pipe_writer_fd = atoi(g_argv[5]);
|
||||||
|
|
||||||
|
// regular file is set with ioctl FIONCLEX
|
||||||
|
struct stat stat_buf;
|
||||||
|
int ret = fstat(regular_file_fd, &stat_buf);
|
||||||
|
if (ret != 0 || !S_ISREG(stat_buf.st_mode)) {
|
||||||
|
THROW_ERROR("fstat regular file fd error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pipe reader is set with ioctl FIOCLEX
|
||||||
|
ret = fstat(pipe_reader_fd, &stat_buf);
|
||||||
|
if (ret != -1 || errno != EBADF) {
|
||||||
|
THROW_ERROR("fstat pipe reader fd error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pipe writer is set with default and should inherit by child
|
||||||
|
ret = fstat(pipe_writer_fd, &stat_buf);
|
||||||
|
if (ret != 0 || !S_ISFIFO(stat_buf.st_mode)) {
|
||||||
|
THROW_ERROR("fstat pipe writer fd error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite
|
// Test suite
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -81,6 +111,8 @@ int start_test(const char *test_name) {
|
|||||||
return test_spawn_attribute_sigmask();
|
return test_spawn_attribute_sigmask();
|
||||||
} else if (strcmp(test_name, "sigdef") == 0) {
|
} else if (strcmp(test_name, "sigdef") == 0) {
|
||||||
return test_spawn_attribute_sigdef();
|
return test_spawn_attribute_sigdef();
|
||||||
|
} else if (strcmp(test_name, "fioclex") == 0) {
|
||||||
|
return test_ioctl_fioclex();
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[child] test case not found\n");
|
fprintf(stderr, "[child] test case not found\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -89,7 +121,7 @@ int start_test(const char *test_name) {
|
|||||||
|
|
||||||
void print_usage() {
|
void print_usage() {
|
||||||
fprintf(stderr, "Usage:\n nauty_child [-t testcase1] [-t testcase2] ...\n\n");
|
fprintf(stderr, "Usage:\n nauty_child [-t testcase1] [-t testcase2] ...\n\n");
|
||||||
fprintf(stderr, " Now support testcase: <sigmask, sigdef>\n");
|
fprintf(stderr, " Now support testcase: <sigmask, sigdef, fioclex>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@ -98,6 +130,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_argv = argv;
|
||||||
int opt;
|
int opt;
|
||||||
char *testcase_name = calloc(1, TEST_NAME_MAX);
|
char *testcase_name = calloc(1, TEST_NAME_MAX);
|
||||||
while ((opt = getopt(argc, argv, "t:")) != -1) {
|
while ((opt = getopt(argc, argv, "t:")) != -1) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -329,6 +330,61 @@ int test_select_read_write() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_ioctl_fionread() {
|
||||||
|
int pipe_fds[2];
|
||||||
|
if (pipe(pipe_fds) < 0) {
|
||||||
|
THROW_ERROR("failed to create a pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
int pipe_rd_fd = pipe_fds[0];
|
||||||
|
int pipe_wr_fd = pipe_fds[1];
|
||||||
|
|
||||||
|
posix_spawn_file_actions_t file_actions;
|
||||||
|
posix_spawn_file_actions_init(&file_actions);
|
||||||
|
posix_spawn_file_actions_adddup2(&file_actions, pipe_wr_fd, STDOUT_FILENO);
|
||||||
|
posix_spawn_file_actions_addclose(&file_actions, pipe_rd_fd);
|
||||||
|
|
||||||
|
const char *msg = "Echo!\n";
|
||||||
|
const char *child_prog = "/bin/hello_world";
|
||||||
|
const char *child_argv[3] = { child_prog, msg, NULL };
|
||||||
|
int child_pid;
|
||||||
|
if (posix_spawn(&child_pid, child_prog, &file_actions,
|
||||||
|
NULL, (char *const *)child_argv, NULL) < 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process");
|
||||||
|
}
|
||||||
|
int status = 0;
|
||||||
|
if (wait4(child_pid, &status, 0, NULL) < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipe_wr_fd);
|
||||||
|
|
||||||
|
const char *expected_str = msg;
|
||||||
|
size_t expected_len = strlen(expected_str);
|
||||||
|
char actual_str[32] = {0};
|
||||||
|
|
||||||
|
int data_len_ready = 0;
|
||||||
|
if ( ioctl(pipe_rd_fd, FIONREAD, &data_len_ready) < 0 ) {
|
||||||
|
THROW_ERROR("ioctl FIONREAD failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// data_len_ready will include '\0'
|
||||||
|
if (data_len_ready - 1 != expected_len) {
|
||||||
|
THROW_ERROR("ioctl FIONREAD value not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(pipe_rd_fd, actual_str, sizeof(actual_str) - 1) < 0) {
|
||||||
|
THROW_ERROR("reading pipe failed");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (strncmp(expected_str, actual_str, expected_len) != 0) {
|
||||||
|
THROW_ERROR("received string is not as expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pipe_rd_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite
|
// Test suite
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -344,6 +400,7 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_poll_no_timeout),
|
TEST_CASE(test_poll_no_timeout),
|
||||||
TEST_CASE(test_epoll_no_timeout),
|
TEST_CASE(test_epoll_no_timeout),
|
||||||
TEST_CASE(test_select_read_write),
|
TEST_CASE(test_select_read_write),
|
||||||
|
TEST_CASE(test_ioctl_fionread),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
int main(int argc, const char *argv[]) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -245,12 +246,61 @@ int test_getname() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_ioctl_fionread() {
|
||||||
|
int ret = 0;
|
||||||
|
int sockets[2];
|
||||||
|
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to create a unix socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *child_prog = "/bin/hello_world";
|
||||||
|
const char *child_argv[3] = { child_prog, ECHO_MSG, NULL };
|
||||||
|
int child_pid;
|
||||||
|
posix_spawn_file_actions_t file_actions;
|
||||||
|
|
||||||
|
posix_spawn_file_actions_init(&file_actions);
|
||||||
|
posix_spawn_file_actions_adddup2(&file_actions, sockets[0], STDOUT_FILENO);
|
||||||
|
posix_spawn_file_actions_addclose(&file_actions, sockets[1]);
|
||||||
|
|
||||||
|
if (posix_spawn(&child_pid, child_prog, &file_actions,
|
||||||
|
NULL, (char *const *)child_argv, NULL) < 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process");
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
if (wait4(child_pid, &status, 0, NULL) < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
|
||||||
|
// data should be ready
|
||||||
|
int data_len_ready = 0;
|
||||||
|
if (ioctl(sockets[1], FIONREAD, &data_len_ready) < 0) {
|
||||||
|
THROW_ERROR("failed to ioctl with FIONREAD option");
|
||||||
|
}
|
||||||
|
|
||||||
|
// data_len_ready will include '\0'
|
||||||
|
if (data_len_ready - 1 != strlen(ECHO_MSG)) {
|
||||||
|
THROW_ERROR("ioctl FIONREAD value not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
char actual_str[32] = {0};
|
||||||
|
read(sockets[1], actual_str, 32);
|
||||||
|
if (strncmp(actual_str, ECHO_MSG, sizeof(ECHO_MSG) - 1) != 0) {
|
||||||
|
printf("data read is :%s\n", actual_str);
|
||||||
|
THROW_ERROR("received string is not as expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static test_case_t test_cases[] = {
|
static test_case_t test_cases[] = {
|
||||||
TEST_CASE(test_unix_socket_inter_process),
|
TEST_CASE(test_unix_socket_inter_process),
|
||||||
TEST_CASE(test_socketpair_inter_process),
|
TEST_CASE(test_socketpair_inter_process),
|
||||||
TEST_CASE(test_multiple_socketpairs),
|
TEST_CASE(test_multiple_socketpairs),
|
||||||
TEST_CASE(test_poll),
|
TEST_CASE(test_poll),
|
||||||
TEST_CASE(test_getname),
|
TEST_CASE(test_getname),
|
||||||
|
TEST_CASE(test_ioctl_fionread),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
int main(int argc, const char *argv[]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user