int main (int argc, char *argv[]) { int test = atoi (argv[1]); int port = atoi (argv[2]); int client_socket; /* Create a client socket. */ client_socket = create_client_socket (port); /* Prepare the file descriptor. */ if (test & 2) ASSERT (set_nonblocking_flag (client_socket, true) >= 0); main_reader_loop (test, SOCKET_DATA_BLOCK_SIZE, client_socket); return 0; }
int main (int argc, char *argv[]) { const char *child_path; int test; int fd[2]; int child; int exitcode; set_program_name (argv[0]); child_path = argv[1]; test = atoi (argv[2]); /* Create a pipe. */ ASSERT (pipe (fd) >= 0); /* Map fd[0] to STDIN_FILENO and fd[1] to STDOUT_FILENO, because on Windows, the only three file descriptors that are inherited by child processes are STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. */ if (fd[0] != STDIN_FILENO) { ASSERT (dup2 (fd[0], STDIN_FILENO) >= 0); close (fd[0]); } if (fd[1] != STDOUT_FILENO) { ASSERT (dup2 (fd[1], STDOUT_FILENO) >= 0); close (fd[1]); } /* Prepare the file descriptors. */ if (test & 1) ASSERT (set_nonblocking_flag (STDOUT_FILENO, true) >= 0); if (test & 2) ASSERT (set_nonblocking_flag (STDIN_FILENO, true) >= 0); /* Spawn the child process. */ { const char *child_argv[3]; child_argv[0] = child_path; child_argv[1] = argv[2]; child_argv[2] = NULL; #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ child = spawnvpe (P_NOWAIT, child_path, child_argv, (const char **) environ); ASSERT (child >= 0); #else { pid_t child_pid; int err = posix_spawnp (&child_pid, child_path, NULL, NULL, (char **) child_argv, environ); ASSERT (err == 0); child = child_pid; } #endif } /* Close unused file descriptors. */ close (STDIN_FILENO); exitcode = main_writer_loop (test, PIPE_DATA_BLOCK_SIZE, STDOUT_FILENO, false); { int err = wait_subprocess (child, child_path, false, false, false, false, NULL); ASSERT (err == 0); } return exitcode; }
int pipe2 (int fd[2], int flags) { /* Mingw _pipe() corrupts fd on failure; also, if we succeed at creating the pipe but later fail at changing fcntl, we want to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */ int tmp[2]; tmp[0] = fd[0]; tmp[1] = fd[1]; #if HAVE_PIPE2 # undef pipe2 /* Try the system call first, if it exists. (We may be running with a glibc that has the function but with an older kernel that lacks it.) */ { /* Cache the information whether the system call really exists. */ static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */ if (have_pipe2_really >= 0) { int result = pipe2 (fd, flags); if (!(result < 0 && errno == ENOSYS)) { have_pipe2_really = 1; return result; } have_pipe2_really = -1; } } #endif /* Check the supported flags. */ if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0) { errno = EINVAL; return -1; } #if defined _WIN32 && ! defined __CYGWIN__ /* Native Windows API. */ if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0) { fd[0] = tmp[0]; fd[1] = tmp[1]; return -1; } /* O_NONBLOCK handling. On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the functions defined by the gnulib module 'nonblocking'. */ # if GNULIB_defined_O_NONBLOCK if (flags & O_NONBLOCK) { if (set_nonblocking_flag (fd[0], true) != 0 || set_nonblocking_flag (fd[1], true) != 0) goto fail; } # else { verify (O_NONBLOCK == 0); } # endif return 0; #else /* Unix API. */ if (pipe (fd) < 0) return -1; /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html> says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on both fd[0] and fd[1]. */ /* O_NONBLOCK handling. On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */ if (flags & O_NONBLOCK) { int fcntl_flags; if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0 || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1 || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0 || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1) goto fail; } if (flags & O_CLOEXEC) { int fcntl_flags; if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0 || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1 || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0 || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) goto fail; } # if O_BINARY if (flags & O_BINARY) { set_binary_mode (fd[1], O_BINARY); set_binary_mode (fd[0], O_BINARY); } else if (flags & O_TEXT) { set_binary_mode (fd[1], O_TEXT); set_binary_mode (fd[0], O_TEXT); } # endif return 0; #endif #if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__) fail: { int saved_errno = errno; close (fd[0]); close (fd[1]); fd[0] = tmp[0]; fd[1] = tmp[1]; errno = saved_errno; return -1; } #endif }
int main (int argc, char *argv[]) { const char *child_path = argv[1]; int test = atoi (argv[2]); int server; int port; int child; int server_socket; int exitcode; /* Create a server socket. */ server = create_server (0, 1, &port); /* Spawn the child process. */ { char port_arg[10+1]; const char *child_argv[4]; sprintf (port_arg, "%u", port); child_argv[0] = child_path; child_argv[1] = argv[2]; child_argv[2] = port_arg; child_argv[3] = NULL; #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ child = spawnvpe (P_NOWAIT, child_path, child_argv, (const char **) environ); ASSERT (child >= 0); #else { pid_t child_pid; int err = posix_spawnp (&child_pid, child_path, NULL, NULL, (char **) child_argv, environ); ASSERT (err == 0); child = child_pid; } #endif } /* Accept a connection from the child process. */ server_socket = create_server_socket (server); /* Prepare the file descriptor. */ if (test & 1) ASSERT (set_nonblocking_flag (server_socket, true) >= 0); #if ENABLE_DEBUGGING # ifdef SO_SNDBUF { int value; socklen_t value_len = sizeof (value); if (getsockopt (server_socket, SOL_SOCKET, SO_SNDBUF, &value, &value_len) >= 0) fprintf (stderr, "SO_SNDBUF = %d\n", value); } # endif # ifdef SO_RCVBUF { int value; socklen_t value_len = sizeof (value); if (getsockopt (server_socket, SOL_SOCKET, SO_RCVBUF, &value, &value_len) >= 0) fprintf (stderr, "SO_RCVBUF = %d\n", value); } # endif #endif exitcode = main_writer_loop (test, SOCKET_DATA_BLOCK_SIZE, server_socket, SOCKET_HAS_LARGE_BUFFER); { int err = wait_subprocess (child, child_path, false, false, false, false, NULL); ASSERT (err == 0); } return exitcode; }