コード例 #1
0
ファイル: pty.c プロジェクト: gbl/vte
/**
 * 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
}
コード例 #2
0
ファイル: pty_open.c プロジェクト: GNOME/vinagre
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;
}
コード例 #3
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;
}
コード例 #4
0
ファイル: pty_open.c プロジェクト: GNOME/vinagre
/* 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;
}
コード例 #5
0
ファイル: pty_open.c プロジェクト: GNOME/vinagre
/* 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;
}
コード例 #6
0
ファイル: pty.c プロジェクト: gbl/vte
/*
 * _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;
}