Пример #1
0
int libvchan_write(struct libvchan *ctrl, const void *data, size_t size)
{
    int avail;
    if (!libvchan_is_open(ctrl))
        return -1;
    if (ctrl->blocking) {
        size_t pos = 0;
        while (1) {
            avail = libvchan_buffer_space(ctrl);
            if (pos + avail > size)
                avail = size - pos;
            if (avail)
                pos += do_send(ctrl, data + pos, avail);
            if (pos == size)
                return pos;
            if (libvchan_wait(ctrl))
                return -1;
            if (!libvchan_is_open(ctrl))
                return -1;
        }
    } else {
        avail = libvchan_buffer_space(ctrl);
        if (size > avail)
            size = avail;
        if (size == 0)
            return 0;
        return do_send(ctrl, data, size);
    }
}
Пример #2
0
int main()
{
    fd_set rdset, wrset;
    int max;
    sigset_t chld_set;

    init();
    signal(SIGCHLD, sigchld_handler);
    signal(SIGPIPE, SIG_IGN);
    sigemptyset(&chld_set);
    sigaddset(&chld_set, SIGCHLD);


    for (;;) {
        sigprocmask(SIG_BLOCK, &chld_set, NULL);
        if (child_exited)
            reap_children();
        max = fill_fds_for_select(&rdset, &wrset);
        if (libvchan_buffer_space(ctrl_vchan) <=
                (int)sizeof(struct msg_header))
            FD_ZERO(&rdset);

        wait_for_vchan_or_argfd(ctrl_vchan, max, &rdset, &wrset);
        sigprocmask(SIG_UNBLOCK, &chld_set, NULL);

        while (libvchan_data_ready(ctrl_vchan))
            handle_server_cmd();

        if (FD_ISSET(trigger_fd, &rdset))
            handle_trigger_io();

        handle_terminated_fork_client(&rdset);
    }
}
Пример #3
0
static void handle_input(libvchan_t *vchan)
{
    char buf[MAX_DATA_CHUNK];
    int ret;
    size_t max_len;
    struct msg_header hdr;

    max_len = libvchan_buffer_space(vchan)-sizeof(hdr);
    if (max_len > sizeof(buf))
        max_len = sizeof(buf);
    if (max_len == 0)
        return;
    ret = read(local_stdout_fd, buf, max_len);
    if (ret < 0) {
        perror("read");
        do_exit(1);
    }
    hdr.type = is_service ? MSG_DATA_STDOUT : MSG_DATA_STDIN;
    hdr.len = ret;
    if (libvchan_send(vchan, &hdr, sizeof(hdr)) != sizeof(hdr)) {
        fprintf(stderr, "Failed to write STDIN data to the agent\n");
        do_exit(1);
    }
    if (ret == 0) {
        close(local_stdout_fd);
        local_stdout_fd = -1;
        if (local_stdin_fd == -1) {
            // if not a remote end of service call, wait for exit status
            if (is_service) {
                // if pipe in opposite direction already closed, no need to stay alive
                if (local_pid == 0) {
                    /* if this is "remote" service end and no real local process
                     * exists (using own stdin/out) send also fake exit code */
                    send_exit_code(vchan, 0);
                    do_exit(0);
                }
            }
        }
    }
    if (!write_vchan_all(vchan, buf, ret)) {
        if (!libvchan_is_open(vchan)) {
            // agent disconnected its end of socket, so no future data will be
            // send there; there is no sense to read from child stdout
            //
            // since vchan socket is buffered it doesn't mean all data was
            // received from the agent
            close(local_stdout_fd);
            local_stdout_fd = -1;
            if (local_stdin_fd == -1) {
                // since child does no longer accept data on its stdin, doesn't
                // make sense to process the data from the daemon
                //
                // we don't know real exit VM process code (exiting here, before
                // MSG_DATA_EXIT_CODE message)
                do_exit(1);
            }
        } else
            perror("write agent");
    }
}
int main(int argc, char **argv)
{
    fd_set read_fdset, write_fdset;
    int i, opt;
    int max;
    sigset_t chld_set;

    while ((opt=getopt(argc, argv, "q")) != -1) {
        switch (opt) {
            case 'q':
                opt_quiet = 1;
                break;
            default: /* '?' */
                fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]);
                exit(1);
        }
    }
    if (argc - optind < 2 || argc - optind > 3) {
        fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]);
        exit(1);
    }
    remote_domain_id = atoi(argv[optind]);
    remote_domain_name = argv[optind+1];
    if (argc - optind >= 3)
        default_user = argv[optind+2];
    init(remote_domain_id);
    sigemptyset(&chld_set);
    sigaddset(&chld_set, SIGCHLD);
    signal(SIGCHLD, sigchld_handler);
    /*
     * The main event loop. Waits for one of the following events:
     * - message from client
     * - message from agent
     * - new client
     * - child exited
     */
    for (;;) {
        max = fill_fdsets_for_select(&read_fdset, &write_fdset);
        if (libvchan_buffer_space(vchan) <= (int)sizeof(struct msg_header))
            FD_ZERO(&read_fdset);	// vchan full - don't read from clients

        sigprocmask(SIG_BLOCK, &chld_set, NULL);
        if (child_exited)
            reap_children();
        wait_for_vchan_or_argfd(vchan, max, &read_fdset, &write_fdset);
        sigprocmask(SIG_UNBLOCK, &chld_set, NULL);

        if (FD_ISSET(qrexec_daemon_unix_socket_fd, &read_fdset))
            handle_new_client();

        while (libvchan_data_ready(vchan))
            handle_message_from_agent();

        for (i = 0; i <= max_client_fd; i++)
            if (clients[i].state != CLIENT_INVALID
                && FD_ISSET(i, &read_fdset))
                handle_message_from_client(i);
    }
}
Пример #5
0
int write_data(libvchan_t *vchan, char *buf, int size)
{
	int count;
	if (!double_buffered)
		return write_data_exact(vchan, buf, size); // this may block
	double_buffer_append(buf, size);
	count = libvchan_buffer_space(vchan);
	if (count > double_buffer_datacount())
		count = double_buffer_datacount();
        // below, we write only as much data as possible without
        // blocking; remainder of data stays in the double buffer
	write_data_exact(vchan, double_buffer_data(), count);
	double_buffer_substract(count);
	return size;
}
static int process_sink_render(struct userdata *u)
{
    pa_assert(u);

    if (u->memchunk_sink.length <= 0)
        pa_sink_render(u->sink, libvchan_buffer_space(u->play_ctrl), &u->memchunk_sink);

    pa_assert(u->memchunk_sink.length > 0);

    for (;;) {
        ssize_t l;
        void *p;

        p = pa_memblock_acquire(u->memchunk_sink.memblock);
        l = write_to_vchan(u->play_ctrl, (char *) p +
                           u->memchunk_sink.index, u->memchunk_sink.length);
        pa_memblock_release(u->memchunk_sink.memblock);

        pa_assert(l != 0);

        if (l < 0) {

            if (errno == EINTR)
                continue;
            else if (errno == EAGAIN)
                return 0;
            else {
                pa_log
                ("Failed to write data to VCHAN: %s",
                 pa_cstrerror(errno));
                return -1;
            }

        } else {

            u->memchunk_sink.index += (size_t) l;
            u->memchunk_sink.length -= (size_t) l;

            if (u->memchunk_sink.length <= 0) {
                pa_memblock_unref(u->memchunk_sink.memblock);
                pa_memchunk_reset(&u->memchunk_sink);
            }
        }

        return 0;
    }
}
Пример #7
0
/**
 * returns 0 if no buffer space is available, -1 on error, or size on success
 */
int libvchan_send(struct libvchan *ctrl, const void *data, size_t size)
{
    int avail;
    while (1) {
        if (!libvchan_is_open(ctrl))
            return -1;
        avail = libvchan_buffer_space(ctrl);
        if (size <= avail)
            return do_send(ctrl, data, size);
        if (!ctrl->blocking)
            return 0;
        if (size > wr_ring_size(ctrl))
            return -1;
        if (libvchan_wait(ctrl))
            return -1;
    }
}
Пример #8
0
/**
        may sleep (only if no buffer space available);
        may write less data than requested;
        returns the amount of data processed, -1 on error or peer close
*/        
int libvchan_write(struct libvchan *ctrl, const char *data, int size)
{
	int avail, avail_contig;
	int real_idx;
	while ((avail = libvchan_buffer_space(ctrl)) == 0)
		if (libvchan_wait(ctrl) < 0)
			return -1;
	if (avail > size)
		avail = size;
	real_idx = (*ctrl->wr_prod) & (ctrl->wr_ring_size - 1);
	avail_contig = ctrl->wr_ring_size - real_idx;
	if (avail_contig < avail)
		avail = avail_contig;
	memcpy(ctrl->wr_ring + real_idx, data, avail);
	*ctrl->wr_prod += avail;
	if (do_notify(ctrl) < 0)
		return -1;
	return avail;
}
static int write_to_vchan(libvchan_t *ctrl, char *buf, int size)
{
    static int all = 0, waited = 0, nonwaited = 0, full = 0;
    ssize_t l;
    fd_set rfds;
    struct timeval tv = { 0, 0 };
    int ret, fd = libvchan_fd_for_select(ctrl);
    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);
    all++;
    ret = select(fd + 1, &rfds, NULL, NULL, &tv);
    if (ret == -1) {
        pa_log("Failed to select() in vchan: %s",
               pa_cstrerror(errno));
        return -1;
    }
    if (ret) {
        if (libvchan_wait(ctrl) < 0) {
            pa_log("Failed libvchan_wait");
            return -1;
        }
        waited++;
    } else
        nonwaited++;
    if (libvchan_buffer_space(ctrl)) {
        l = libvchan_write(ctrl, buf, size);
    } else {
        l = -1;
        errno = EAGAIN;
        full++;
    }
    if ((all % 8000) == 0) {
        pa_log
        ("write_to_vchan: all=%d waited=%d nonwaited=%d full=%d\n",
         all, waited, nonwaited, full);
    }
    return l;
}
static void thread_func(void *userdata)
{
    struct userdata *u = userdata;
    char buf[2048]; // max ring buffer size

    pa_assert(u);

    pa_log_debug("Thread starting up");

    pa_thread_mq_install(&u->thread_mq);
    for (;;) {
        struct pollfd *play_pollfd;
        struct pollfd *rec_pollfd;
        int ret;

        play_pollfd = pa_rtpoll_item_get_pollfd(u->play_rtpoll_item, NULL);
        rec_pollfd = pa_rtpoll_item_get_pollfd(u->rec_rtpoll_item, NULL);

        if (play_pollfd->revents & POLLIN) {
            if (libvchan_wait(u->play_ctrl) < 0)
                goto fail;
            play_pollfd->revents = 0;
        }

        if (rec_pollfd->revents & POLLIN) {
            if (libvchan_wait(u->rec_ctrl) < 0)
                goto fail;
            rec_pollfd->revents = 0;
        }

        /* Render some data and write it to the fifo */
        if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {

            if (u->sink->thread_info.rewind_requested)
                pa_sink_process_rewind(u->sink, 0);

            if (libvchan_buffer_space(u->play_ctrl)) {
                if (process_sink_render(u) < 0)
                    goto fail;
            }
        }

        if (u->source->thread_info.state == PA_SOURCE_RUNNING) {
            while (libvchan_data_ready(u->rec_ctrl)) {
                if (process_source_data(u) < 0)
                    goto fail;
            }
        } else {
            /* discard the data */
            if (libvchan_data_ready(u->rec_ctrl))
                if (libvchan_read(u->rec_ctrl, buf, sizeof(buf)) < 0)
                    goto fail;
        }

        /* Hmm, nothing to do. Let's sleep */
        play_pollfd->events = POLLIN;
        rec_pollfd->events = POLLIN;

#if PA_CHECK_VERSION(6,0,0)
        if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
#else
        if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
#endif
            goto fail;

        if (ret == 0)
            goto finish;
    }

fail:
    /* If this was no regular exit from the loop we have to continue
     * processing messages until we received PA_MESSAGE_SHUTDOWN */
    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core),
                      PA_CORE_MESSAGE_UNLOAD_MODULE, u->module,
                      0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);

finish:
    pa_log_debug("Thread shutting down");
}
Пример #11
0
static void select_loop(libvchan_t *vchan)
{
    fd_set select_set;
    fd_set wr_set;
    int max_fd;
    int ret;
    int vchan_fd;
    sigset_t selectmask;
    struct timespec zero_timeout = { 0, 0 };
    struct timespec select_timeout = { 10, 0 };
    struct buffer stdin_buf;

    sigemptyset(&selectmask);
    sigaddset(&selectmask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &selectmask, NULL);
    sigemptyset(&selectmask);
    buffer_init(&stdin_buf);
    /* remember to set back to blocking mode before closing the FD - this may
     * be not the only copy and some processes may misbehave when get
     * nonblocking FD for input/output
     */
    set_nonblock(local_stdin_fd);

    for (;;) {
        vchan_fd = libvchan_fd_for_select(vchan);
        FD_ZERO(&select_set);
        FD_ZERO(&wr_set);
        FD_SET(vchan_fd, &select_set);
        max_fd = vchan_fd;
        if (local_stdout_fd != -1 &&
                (size_t)libvchan_buffer_space(vchan) > sizeof(struct msg_header)) {
            FD_SET(local_stdout_fd, &select_set);
            if (local_stdout_fd > max_fd)
                max_fd = local_stdout_fd;
        }
        if (child_exited && local_stdout_fd == -1)
            check_child_status(vchan);
        if (local_stdin_fd != -1 && buffer_len(&stdin_buf)) {
            FD_SET(local_stdin_fd, &wr_set);
            if (local_stdin_fd > max_fd)
                max_fd = local_stdin_fd;
        }
        if ((local_stdin_fd == -1 || buffer_len(&stdin_buf) == 0) &&
                libvchan_data_ready(vchan) > 0) {
            /* check for other FDs, but exit immediately */
            ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
                    &zero_timeout, &selectmask);
        } else
            ret = pselect(max_fd + 1, &select_set, &wr_set, NULL,
                    &select_timeout, &selectmask);
        if (ret < 0) {
            if (errno == EINTR && local_pid > 0) {
                continue;
            } else {
                perror("select");
                do_exit(1);
            }
        }
        if (ret == 0) {
            if (!libvchan_is_open(vchan)) {
                /* remote disconnected witout a proper signaling */
                do_exit(1);
            }
        }
        if (FD_ISSET(vchan_fd, &select_set))
            libvchan_wait(vchan);
        if (buffer_len(&stdin_buf) &&
                local_stdin_fd != -1 &&
                FD_ISSET(local_stdin_fd, &wr_set)) {
            if (flush_client_data(local_stdin_fd, &stdin_buf) == WRITE_STDIN_ERROR) {
                perror("write stdin");
                close(local_stdin_fd);
                local_stdin_fd = -1;
            }
        }
        while (libvchan_data_ready(vchan))
            if (handle_vchan_data(vchan, &stdin_buf) != WRITE_STDIN_OK)
                break;

        if (local_stdout_fd != -1
                && FD_ISSET(local_stdout_fd, &select_set))
            handle_input(vchan);
    }
}