Exemple #1
0
/* 
The header (hdr argument) is already built. Just read the raw data from
the packet, and pass it along with the header to the client.
*/
void get_packet_data_from_agent_and_pass_to_client(int client_id, struct client_header
						   *hdr)
{
	int len = hdr->len;
	char buf[sizeof(*hdr) + len];

	/* make both the header and data be consecutive in the buffer */
	*(struct client_header *) buf = *hdr;
	read_all_vchan_ext(buf + sizeof(*hdr), len);

	switch (write_stdin
		(client_id, client_id, buf, len + sizeof(*hdr),
		 &clients[client_id].buffer)) {
	case WRITE_STDIN_OK:
		break;
	case WRITE_STDIN_BUFFERED:	// some data have been buffered
		clients[client_id].state |= CLIENT_OUTQ_FULL;
		break;
	case WRITE_STDIN_ERROR:
		terminate_client_and_flush_data(client_id);
		break;
	default:
		fprintf(stderr, "unknown write_stdin?\n");
		exit(1);
	}
}
static int handle_vchan_data(libvchan_t *vchan, struct buffer *stdin_buf)
{
    int status;
    struct msg_header hdr;
    char buf[MAX_DATA_CHUNK];

    if (local_stdin_fd != -1) {
        switch(flush_client_data(local_stdin_fd, stdin_buf)) {
            case WRITE_STDIN_ERROR:
                perror("write stdin");
                close(local_stdin_fd);
                local_stdin_fd = -1;
                break;
            case WRITE_STDIN_BUFFERED:
                return WRITE_STDIN_BUFFERED;
            case WRITE_STDIN_OK:
                break;
        }
    }
    if (libvchan_recv(vchan, &hdr, sizeof hdr) < 0) {
        perror("read vchan");
        do_exit(1);
    }
    if (hdr.len > MAX_DATA_CHUNK) {
        fprintf(stderr, "client_header.len=%d\n", hdr.len);
        do_exit(1);
    }
    if (!read_vchan_all(vchan, buf, hdr.len)) {
        perror("read daemon");
        do_exit(1);
    }

    switch (hdr.type) {
        /* both directions because we can serve as either end of service call */
        case MSG_DATA_STDIN:
        case MSG_DATA_STDOUT:
            if (local_stdin_fd == -1)
                break;
            if (replace_esc_stdout)
                do_replace_esc(buf, hdr.len);
            if (hdr.len == 0) {
                /* restore flags, as we may have not the only copy of this file descriptor
                */
                if (local_stdin_fd != -1)
                    set_block(local_stdin_fd);
                close(local_stdin_fd);
                local_stdin_fd = -1;
            } else {
                switch (write_stdin(local_stdin_fd, buf, hdr.len, stdin_buf)) {
                    case WRITE_STDIN_BUFFERED:
                        return WRITE_STDIN_BUFFERED;
                    case WRITE_STDIN_ERROR:
                        if (errno == EPIPE) {
                            // local process have closed its stdin, handle data in oposite
                            // direction (if any) before exit
                            close(local_stdin_fd);
                            local_stdin_fd = -1;
                        } else {
                            perror("write local stdout");
                            do_exit(1);
                        }
                        break;
                    case WRITE_STDIN_OK:
                        break;
                }
            }
            break;
        case MSG_DATA_STDERR:
            if (replace_esc_stderr)
                do_replace_esc(buf, hdr.len);
            write_all(2, buf, hdr.len);
            break;
        case MSG_DATA_EXIT_CODE:
            libvchan_close(vchan);
            if (hdr.len < sizeof(status))
                status = 255;
            else
                memcpy(&status, buf, sizeof(status));

            flush_client_data(local_stdin_fd, stdin_buf);
            do_exit(status);
            break;
        default:
            fprintf(stderr, "unknown msg %d\n", hdr.type);
            do_exit(1);
    }
    /* intentionally do not distinguish between _ERROR and _OK, because in case
     * of write error, we simply eat the data - no way to report it to the
     * other side */
    return WRITE_STDIN_OK;
}