/** * vte_pty_close: * @pty: a #VtePty * * Cleans up the PTY, specifically any logging performed for the session. * The file descriptor to the PTY master remains open. */ void vte_pty_close (VtePty *pty) { #ifdef VTE_USE_GNOME_PTY_HELPER VtePtyPrivate *priv = pty->priv; gpointer tag; GnomePtyOps ops; if (!priv->using_helper) return; /* Signal the helper that it needs to close its connection. */ tag = priv->helper_tag; ops = GNOME_PTY_CLOSE_PTY; if (n_write(_vte_pty_helper_tunnel, &ops, sizeof(ops)) != sizeof(ops)) { return; } if (n_write(_vte_pty_helper_tunnel, &tag, sizeof(tag)) != sizeof(tag)) { return; } ops = GNOME_PTY_SYNCH; if (n_write(_vte_pty_helper_tunnel, &ops, sizeof(ops)) != sizeof(ops)) { return; } n_read(_vte_pty_helper_tunnel, &ops, 1); priv->helper_tag = NULL; priv->using_helper = FALSE; #endif }
int main(int argc, char **argv) { pid_t child = 0; char c; int ret; signal(SIGCHLD, sigchld_handler); fd = pty_open(&child, 0, NULL, (argc > 1) ? argv[1] : NULL, (argc > 1) ? argv + 1 : NULL, NULL, 0, 0, NULL, NULL, NULL); if (child == 0) { int i; for (i = 0; ; i++) { switch (i % 3) { case 0: case 1: fprintf(stdout, "%d\n", i); break; case 2: fprintf(stderr, "%d\n", i); break; default: g_assert_not_reached(); break; } sleep(1); } } g_print("Child pid is %d.\n", (int)child); do { ret = n_read(fd, &c, 1); if (ret == 0) { break; } if ((ret == -1) && (errno != EAGAIN) && (errno != EINTR)) { break; } if (argc < 2) { n_write(STDOUT_FILENO, "[", 1); } n_write(STDOUT_FILENO, &c, 1); if (argc < 2) { n_write(STDOUT_FILENO, "]", 1); } } while (TRUE); return 0; }
void *run_ntttcp_sender_tcp_stream( void *ptr ) { char *log = NULL; bool verbose_log = false; int sockfd = 0; //socket id char *buffer; //send buffer int n = 0; //write n bytes to socket uint64_t nbytes = 0; //total bytes sent int i = 0; //hold function return value struct ntttcp_stream_client *sc; struct sockaddr_storage local_addr; //for local address socklen_t local_addr_size; //local address size char *remote_addr_str; //used to get remote peer's ip address int ip_addr_max_size; //used to get remote peer's ip address char *port_str; //used to get remote peer's port number struct addrinfo hints, *remote_serv_info, *p; //to get remote peer's sockaddr sc = (struct ntttcp_stream_client *) ptr; verbose_log = sc->verbose; /* get address of remote receiver */ memset(&hints, 0, sizeof hints); hints.ai_family = sc->domain; hints.ai_socktype = sc->protocol; asprintf(&port_str, "%d", sc->server_port); if (getaddrinfo(sc->bind_address, port_str, &hints, &remote_serv_info) != 0) { PRINT_ERR("cannot get address info for receiver"); return 0; } free(port_str); /* only get the first entry if connected */ for (p = remote_serv_info; p != NULL; p = p->ai_next) { /* 1. create socket fd */ if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { PRINT_ERR("cannot create socket ednpoint"); freeaddrinfo(remote_serv_info); return 0; } local_addr_size = sizeof(local_addr); /* 2. bind this socket fd to a local random/ephemeral TCP port, so that the sender side will have randomized TCP ports. */ if (sc->domain == AF_INET) { (*(struct sockaddr_in*)&local_addr).sin_family = AF_INET; (*(struct sockaddr_in*)&local_addr).sin_port = htons(sc->client_port); } else{ (*(struct sockaddr_in6*)&local_addr).sin6_family = AF_INET6; (*(struct sockaddr_in6*)&local_addr).sin6_port = htons(sc->client_port); } if (( i = bind(sockfd, (struct sockaddr *)&local_addr, local_addr_size)) < 0 ) { asprintf(&log, "failed to bind socket: %d to a local ephemeral port. errno = %d", sockfd, errno); PRINT_ERR_FREE(log); } /* 3. connect to receiver */ ip_addr_max_size = (sc->domain == AF_INET? INET_ADDRSTRLEN : INET6_ADDRSTRLEN); if ( (remote_addr_str = (char *)malloc(ip_addr_max_size)) == (char *)NULL) { PRINT_ERR("cannot allocate memory for ip address string"); freeaddrinfo(remote_serv_info); return 0; } remote_addr_str = retrive_ip_address_str((struct sockaddr_storage *)p->ai_addr, remote_addr_str, ip_addr_max_size); if (( i = connect(sockfd, p->ai_addr, p->ai_addrlen)) < 0) { if (i == -1) { asprintf(&log, "failed to connect to receiver: %s:%d on socket: %d. errno = %d", remote_addr_str, sc->server_port, sockfd, errno); PRINT_ERR_FREE(log); } else { asprintf(&log, "failed to connect to receiver: %s:%d on socket: %d. error code = %d", remote_addr_str, sc->server_port, sockfd, i); PRINT_ERR_FREE(log); } freeaddrinfo(remote_serv_info); free(remote_addr_str); close(sockfd); return 0; } else{ break; //connected } } /* get local TCP ephemeral port number assigned, for logging */ if (getsockname(sockfd, (struct sockaddr *) &local_addr, &local_addr_size) != 0) { asprintf(&log, "failed to get local address information for socket: %d", sockfd); PRINT_ERR_FREE(log); } asprintf(&log, "New connection: local:%d [socket:%d] --> %s:%d", ntohs(sc->domain == AF_INET? ((struct sockaddr_in *)&local_addr)->sin_port: ((struct sockaddr_in6 *)&local_addr)->sin6_port), sockfd, remote_addr_str, sc->server_port); PRINT_DBG_FREE(log); free(remote_addr_str); freeaddrinfo(remote_serv_info); /* wait for sync thread to finish */ wait_light_on(); if ((buffer = (char *)malloc(sc->send_buf_size * sizeof(char))) == (char *)NULL) { PRINT_ERR("cannot allocate memory for send buffer"); close(sockfd); return 0; } //fill_buffer(buffer, sc->send_buf_size); memset(buffer, 'A', sc->send_buf_size * sizeof(char)); while (is_light_turned_on()){ n = n_write(sockfd, buffer, strlen(buffer)); if (n < 0) { PRINT_ERR("cannot write data to a socket"); free(buffer); close(sockfd); return 0; } nbytes += n; } sc->total_bytes_transferred = nbytes; free(buffer); close(sockfd); return 0; }
/* Open the named PTY slave, fork off a child (storing its PID in child), * and exec the named command in its own session as a process group leader */ static int _pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add, const char *command, char **argv, const char *directory, int columns, int rows, int *stdin_fd, int *stdout_fd, int *stderr_fd, int *held_fd, pid_t *child, gboolean reapchild, gboolean login) { int fd, hold_fd, i; char c; int ready_a[2] = { 0, 0 }; int ready_b[2] = { 0, 0 }; pid_t pid, grandchild_pid; int pid_pipe[2]; int stdin_pipe[2]; int stdout_pipe[2]; int stderr_pipe[2]; /* Optionally hold the slave PTY open in the parent. Needed to prevent * EIO from read() on the master if exec'ing a program that enumerates * and closes open fds before opening /dev/tty (ssh). Partially fixes * bug 644432. */ if (held_fd) { hold_fd = open(path, O_RDWR|O_NOCTTY); if (hold_fd == -1) { return -1; } } /* Open pipes for synchronizing between parent and child. */ if (_pty_pipe_open_bi(&ready_a[0], &ready_a[1], &ready_b[0], &ready_b[1]) == -1) { /* Error setting up pipes. Bail. */ goto bail_ready; } if (reapchild && pipe(pid_pipe)) { /* Error setting up pipes. Bail. */ goto bail_pid; } if (pipe(stdin_pipe)) { /* Error setting up pipes. Bail. */ goto bail_stdin; } if (pipe(stdout_pipe)) { /* Error setting up pipes. Bail. */ goto bail_stdout; } if (pipe(stderr_pipe)) { /* Error setting up pipes. Bail. */ goto bail_stderr; } /* Start up a child. */ pid = fork(); switch (pid) { case -1: /* Error fork()ing. Bail. */ *child = -1; return -1; break; case 0: /* Child. Close the parent's ends of the pipes. */ close(ready_a[0]); close(ready_b[1]); close(stdin_pipe[1]); close(stdout_pipe[0]); close(stderr_pipe[0]); if (held_fd) close(hold_fd); if(reapchild) { close(pid_pipe[0]); /* Fork a intermediate child. This is needed to not * produce zombies! */ grandchild_pid = fork(); if (grandchild_pid < 0) { /* Error during fork! */ n_write (pid_pipe[1], &grandchild_pid, sizeof (grandchild_pid)); _exit (1); } else if (grandchild_pid > 0) { /* Parent! (This is the actual intermediate child; * so write the pid to the parent and then exit */ n_write (pid_pipe[1], &grandchild_pid, sizeof (grandchild_pid)); close (pid_pipe[1]); _exit (0); } /* Start a new session and become process-group leader. */ setsid(); setpgid(0, 0); } /* Close most descriptors. */ for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) { if ((i != ready_b[0]) && (i != ready_a[1]) && (i != stdin_pipe[0]) && (i != stdout_pipe[1]) && (i != stderr_pipe[1])) { close(i); } } /* Set up stdin/out/err */ dup2(stdin_pipe[0], STDIN_FILENO); close (stdin_pipe[0]); dup2(stdout_pipe[1], STDOUT_FILENO); close (stdout_pipe[1]); dup2(stderr_pipe[1], STDERR_FILENO); close (stderr_pipe[1]); /* Open the slave PTY, acquiring it as the controlling terminal * for this process and its children. */ fd = open(path, O_RDWR); if (fd == -1) { return -1; } #ifdef TIOCSCTTY /* TIOCSCTTY is defined? Let's try that, too. */ ioctl(fd, TIOCSCTTY, fd); #endif /* Store 0 as the "child"'s ID to indicate to the caller that * it is now the child. */ *child = 0; return _pty_run_on_pty(fd, login, stdin_pipe[1], stdout_pipe[1], stderr_pipe[1], ready_b[0], ready_a[1], env_add, command, argv, directory); break; default: /* Parent. Close the child's ends of the pipes, do the ready * handshake, and return the child's PID. */ close(ready_b[0]); close(ready_a[1]); close(stdin_pipe[0]); close(stdout_pipe[1]); close(stderr_pipe[1]); if (reapchild) { close(pid_pipe[1]); /* Reap the intermediate child */ wait_again: if (waitpid (pid, NULL, 0) < 0) { if (errno == EINTR) { goto wait_again; } else if (errno == ECHILD) { ; /* NOOP! Child already reaped. */ } else { g_warning ("waitpid() should not fail in pty-open.c"); } } /* * Read the child pid from the pid_pipe * */ if (n_read (pid_pipe[0], child, sizeof (pid_t)) != sizeof (pid_t) || *child == -1) { g_warning ("Error while spanning child!"); goto bail_fork; } close(pid_pipe[0]); } else { /* No intermediate child, simple */ *child = pid; } /* Wait for the child to be ready, set the window size, then * signal that we're ready. We need to synchronize here to * avoid possible races when the child has to do more setup * of the terminal than just opening it. */ n_read(ready_a[0], &c, 1); _pty_set_size(parent_fd, columns, rows); n_write(ready_b[1], &c, 1); close(ready_a[0]); close(ready_b[1]); *stdin_fd = stdin_pipe[1]; *stdout_fd = stdout_pipe[0]; *stderr_fd = stderr_pipe[0]; if (held_fd) *held_fd = hold_fd; return 0; break; } g_assert_not_reached(); return -1; bail_fork: close(stderr_pipe[0]); close(stderr_pipe[1]); bail_stderr: close(stdout_pipe[0]); close(stdout_pipe[1]); bail_stdout: close(stdin_pipe[0]); close(stdin_pipe[1]); bail_stdin: if(reapchild) { close(pid_pipe[0]); close(pid_pipe[1]); } bail_pid: close(ready_a[0]); close(ready_a[1]); close(ready_b[0]); close(ready_b[1]); bail_ready: *child = -1; if (held_fd) close(hold_fd); return -1; }
/* Run the given command (if specified), using the given descriptor as the * controlling terminal. */ static int _pty_run_on_pty(int fd, gboolean login, int stdin_fd, int stdout_fd, int stderr_fd, int ready_reader, int ready_writer, char **env_add, const char *command, char **argv, const char *directory) { int i; char c; char **args, *arg; #ifdef HAVE_STROPTS_H if (!ioctl (fd, I_FIND, "ptem") && ioctl (fd, I_PUSH, "ptem") == -1) { close (fd); _exit (0); return -1; } if (!ioctl (fd, I_FIND, "ldterm") && ioctl (fd, I_PUSH, "ldterm") == -1) { close (fd); _exit (0); return -1; } if (!ioctl (fd, I_FIND, "ttcompat") && ioctl (fd, I_PUSH, "ttcompat") == -1) { perror ("ioctl (fd, I_PUSH, \"ttcompat\")"); close (fd); _exit (0); return -1; } #endif /* HAVE_STROPTS_H */ /* Set any environment variables. */ for (i = 0; (env_add != NULL) && (env_add[i] != NULL); i++) { if (putenv(g_strdup(env_add[i])) != 0) { g_warning("Error adding `%s' to environment, " "continuing.", env_add[i]); } } /* Reset our signals -- our parent may have done any number of * weird things to them. */ _pty_reset_signal_handlers(); /* Change to the requested directory. */ if (directory != NULL) { i = chdir(directory); } #ifdef HAVE_UTMP_H /* This sets stdin, stdout, stderr to the socket */ if (login && login_tty (fd) == -1) { g_printerr ("mount child process login_tty failed: %s\n", g_strerror (errno)); return -1; } #endif /* Signal to the parent that we've finished setting things up by * sending an arbitrary byte over the status pipe and waiting for * a response. This synchronization step ensures that the pty is * fully initialized before the parent process attempts to do anything * with it, and is required on systems where additional setup, beyond * merely opening the device, is required. This is at least the case * on Solaris. */ /* Initialize so valgrind doesn't complain */ c = 0; n_write(ready_writer, &c, 1); fsync(ready_writer); n_read(ready_reader, &c, 1); close(ready_writer); if (ready_writer != ready_reader) { close(ready_reader); } /* If the caller provided a command, we can't go back, ever. */ if (command != NULL) { /* Outta here. */ if (argv != NULL) { for (i = 0; (argv[i] != NULL); i++) ; args = g_malloc0(sizeof(char*) * (i + 1)); for (i = 0; (argv[i] != NULL); i++) { args[i] = g_strdup(argv[i]); } execvp(command, args); } else { arg = g_strdup(command); execlp(command, arg, NULL); } /* Avoid calling any atexit() code. */ _exit(0); g_assert_not_reached(); } return 0; }
/* * _vte_pty_open_with_helper: * @pty: a #VtePty * @error: a location to store a #GError, or %NULL * * Opens a new file descriptor to a new PTY master using the * GNOME PTY helper. * * Returns: %TRUE on success, %FALSE on failure with @error filled in */ static gboolean _vte_pty_open_with_helper(VtePty *pty, GError **error) { VtePtyPrivate *priv = pty->priv; GnomePtyOps ops; int ret; int parentfd = -1, childfd = -1; gpointer tag; /* We have to use the pty helper here. */ if (!_vte_pty_start_helper(error)) return FALSE; /* Try to open a new descriptor. */ ops = _vte_pty_helper_ops_from_flags(priv->flags); /* Send our request. */ if (n_write(_vte_pty_helper_tunnel, &ops, sizeof(ops)) != sizeof(ops)) { g_set_error (error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED, "Failed to send request to gnome-pty-helper: %s", g_strerror(errno)); return FALSE; } _vte_debug_print(VTE_DEBUG_PTY, "Sent request to helper.\n"); /* Read back the response. */ if (n_read(_vte_pty_helper_tunnel, &ret, sizeof(ret)) != sizeof(ret)) { g_set_error (error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED, "Failed to read response from gnome-pty-helper: %s", g_strerror(errno)); return FALSE; } _vte_debug_print(VTE_DEBUG_PTY, "Received response from helper.\n"); if (ret == 0) { g_set_error_literal (error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED, "gnome-pty-helper failed to open pty"); return FALSE; } _vte_debug_print(VTE_DEBUG_PTY, "Helper returns success.\n"); /* Read back a tag. */ if (n_read(_vte_pty_helper_tunnel, &tag, sizeof(tag)) != sizeof(tag)) { g_set_error (error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED, "Failed to read tag from gnome-pty-helper: %s", g_strerror(errno)); return FALSE; } _vte_debug_print(VTE_DEBUG_PTY, "Tag = %p.\n", tag); /* Receive the master and slave ptys. */ _vte_pty_read_ptypair(_vte_pty_helper_tunnel, &parentfd, &childfd); if ((parentfd == -1) || (childfd == -1)) { int errsv = errno; close(parentfd); close(childfd); g_set_error (error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED, "Failed to read master or slave pty from gnome-pty-helper: %s", g_strerror(errsv)); errno = errsv; return FALSE; } _vte_debug_print(VTE_DEBUG_PTY, "Got master pty %d and slave pty %d.\n", parentfd, childfd); priv->using_helper = TRUE; priv->helper_tag = tag; priv->pty_fd = parentfd; priv->child_setup_data.mode = TTY_OPEN_BY_FD; priv->child_setup_data.tty.fd = childfd; return TRUE; }