int main() { arena = Arena_new(); start_socket_server(); start_socket_client(); test_unconnected_put(); //fatal, reconnect start_socket_client(); test_con(); test_con_2(); //fatal, reconnect start_socket_client(); test_con(); test_put(); test_read(); test_take(); test_upt(); //fatal, reconnect start_socket_client(); test_con(); test_upl(); stop_socket_server(); return 0; }
void test_open_socket_fork(void) { /* This subtest will start a server and client using TCP. The client will * open the socket with SOCK_CLOEXEC turned off, so that after a fork+exec, the * socket should stay valid. * o * / | * server | * (accept) | * | | \ * | | client * | | (connect) * | | | \ * | | | client_fork * | | | (exec t67a) * (read) | | (write) * | | | / * | | (waitpid client_fork) * \ | | * (waitpid server) | * | / * (waitpid client) * | * o */ pid_t pid_server, pid_client; int result; pid_server = fork(); if (pid_server < 0) e(1); if (pid_server == 0) { start_socket_server(FORK_PORT); return; /* Never reached */ } pid_client = fork(); if (pid_client < 0) e(2); if (pid_client == 0) { pid_t pid_client_fork; int sockfd; sockfd = start_socket_client(FORK_PORT, 0); if (sockfd < 0) e(4); pid_client_fork = fork(); if (pid_client_fork < 0) { e(5); exit(5); } if (pid_client_fork == 0) { /* We're a fork of the client. After we exec, the * socket should stay valid due to lack of SOCK_CLOEXEC * flag. */ char sockfd_buf[2]; int flags; /* Verify O_CLOEXEC is off */ flags = fcntl(sockfd, F_GETFD); if (flags < 0) e(5); if (flags & FD_CLOEXEC) e(6); /* t67a will verify that it can't write to sockfd and * that opening a new file will yield a file descriptor * with a higher number. */ snprintf(sockfd_buf, sizeof(sockfd_buf), "%d", sockfd); execl("./t67a", "t67a", sockfd_buf, NULL); /* Should not reach this */ exit(1); } else { if (waitpid(pid_client_fork, &result, 0) < 0) e(8); exit(WEXITSTATUS(result)); /* Pass on error to main */ } exit(0); /* Never reached */ } if (waitpid(pid_server, &result, 0) < 0) e(3); if (waitpid(pid_client, &result, 0) < 0) e(4); /* Let's inspect client result */ if (WEXITSTATUS(result) != 0) e(5); }
/** * Start a client for either type of remote connection. Work out * whether the arguments request a remote shell or rsyncd connection, * and call the appropriate connection function, then run_client. * * Calls either start_socket_client (for sockets) or do_cmd and * client_run (for ssh). **/ static int start_client(int argc, char *argv[]) { char *p; char *shell_machine = NULL; char *shell_path = NULL; char *shell_user = NULL; int ret; pid_t pid; int f_in,f_out; int rc; /* Don't clobber argv[] so that ps(1) can still show the right * command line. */ if ((rc = copy_argv(argv))) return rc; if (!read_batch) { /* for read_batch, NO source is specified */ argc--; shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); if (shell_path) { /* source is remote */ argv++; if (filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } if (rsync_port) { if (!shell_cmd) { return start_socket_client(shell_machine, shell_path, argc, argv); } daemon_over_rsh = 1; } am_sender = 0; } else { /* source is local, check dest arg */ am_sender = 1; if (argc < 1) { /* destination required */ usage(FERROR); exit_cleanup(RERR_SYNTAX); } shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port); if (shell_path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } if (!shell_path) { /* no hostspec found, so src & dest are local */ local_server = 1; if (filesfrom_host) { rprintf(FERROR, "--files-from cannot be remote when the transfer is local\n"); exit_cleanup(RERR_SYNTAX); } shell_machine = NULL; shell_path = argv[argc]; } else if (rsync_port) { if (!shell_cmd) { return start_socket_client(shell_machine, shell_path, argc, argv); } daemon_over_rsh = 1; } } } else { /* read_batch */ local_server = 1; shell_path = argv[argc-1]; if (check_for_hostspec(shell_path, &shell_machine, &rsync_port)) { rprintf(FERROR, "remote destination is not allowed with --read-batch\n"); exit_cleanup(RERR_SYNTAX); } } if (shell_machine) { p = strrchr(shell_machine,'@'); if (p) { *p = 0; shell_user = shell_machine; shell_machine = p+1; } } if (verbose > 3) { rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n", shell_cmd ? safe_fname(shell_cmd) : "", shell_machine ? safe_fname(shell_machine) : "", shell_user ? safe_fname(shell_user) : "", shell_path ? safe_fname(shell_path) : ""); } /* for remote source, only single dest arg can remain ... */ if (!am_sender && argc > 1) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } /* ... or no dest at all */ if (!am_sender && argc == 0) list_only |= 1; pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path, &f_in,&f_out); /* if we're running an rsync server on the remote host over a * remote shell command, we need to do the RSYNCD protocol first */ if (daemon_over_rsh) { int tmpret; tmpret = start_inband_exchange(shell_user, shell_path, f_in, f_out, argc); if (tmpret < 0) return tmpret; } ret = client_run(f_in, f_out, pid, argc, argv); fflush(stdout); fflush(stderr); return ret; }