/* 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; }