static void puffout_strings(libvchan_t * con) { size_t sz, len; vchan_header_t head; DPRINTF(DBG_SERVER,"hello: waiting for hello message\n"); /* Wait for hello */ libvchan_wait(con); sz = libvchan_read(con, &head, sizeof(head)); assert(sz == sizeof(head)); assert(head.msg_type == MSG_HELLO); head.msg_type = MSG_ACK; len = head.len; DPRINTF(DBG_SERVER,"hello: sending hello msg ack\n"); /* Send off ack */ sz = libvchan_write(con, &head, sizeof(head)); assert(sz == sizeof(head)); DPRINTF(DBG_SERVER,"hello: waiting for string\n"); /* Read data */ libvchan_wait(con); sz = libvchan_read(con, &char_buf, len); assert(sz == len); DPRINTF(DBG_SERVER,"hello: got string: %s\n", char_buf); // head.msg_type = MSG_CONC; // sz = libvchan_write(con, &head, sizeof(head)); // assert(sz == sizeof(head)); }
static void rec_packet(libvchan_t * con) { char done = 1; int data[4]; struct camera_data ca; libvchan_wait(con); int readSize = libvchan_recv(con, data, 4*sizeof(int)); assert(readSize == 4*sizeof(int)); DVM("received bounding box packet\n"); //here are your corners Lee! ca.bbox_l = data[0]; ca.bbox_r = data[1]; ca.bbox_t = data[2]; ca.bbox_b = data[3]; /* int xmid = ((r + l) / 2) - 160; */ /* int ymid = ((b + t) / 2) - 100; */ /* ymid = -1.0*ymid; //sign change (based on how the camera is oriented) */ /* //here are your angles Lee! */ /* ca.angle_x = ((float) xmid)*(0.00410666); */ /* ca.angle_y = ((float) ymid)*(0.00410666); */ if (camera_vm_Output_from_vm_0_write_camera_data(&ca)) { DVM("wrote bounding box\n"); } else { DVM("failed to write bouding box\n"); } DVM("camera_vm: sending ack\n"); libvchan_send(con, &done, sizeof(char)); }
/** Wait fot the writes to finish, then notify the peer of closing On server side, it waits for the peer to acknowledge */ int libvchan_close(struct libvchan *ctrl) { while (*ctrl->wr_prod != *ctrl->wr_cons) if (libvchan_wait(ctrl) < 0) return -1; if (ctrl->is_server) { ctrl->ring->server_closed = 1; do_notify(ctrl); while (!ctrl->ring->client_closed && libvchan_wait(ctrl) == 0); } else { ctrl->ring->client_closed = 1; do_notify(ctrl); } return 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); } }
static void rec_packet(libvchan_t * con) { size_t sz; int x; char comp[6]; vchan_packet_t pak; for(x = 0; x < NUM_PACKETS; x++) { sprintf(comp, "I%d", x); libvchan_wait(con); sz = libvchan_read(con, &pak, sizeof(pak)); assert(sz == sizeof(pak)); assert(strcmp(comp, pak.pnum) == 0); } }
int libvchan_read(struct libvchan *ctrl, void *data, size_t size) { while (1) { int avail = libvchan_data_ready(ctrl); if (avail && size > avail) size = avail; if (avail) return do_recv(ctrl, data, size); if (!libvchan_is_open(ctrl)) return -1; if (!ctrl->blocking) return 0; if (libvchan_wait(ctrl)) return -1; } }
/** * 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; } }
void init() { mode_t old_umask; /* FIXME: This 0 is remote domain ID */ ctrl_vchan = libvchan_server_init(0, VCHAN_BASE_PORT, 4096, 4096); if (!ctrl_vchan) handle_vchan_error("server_init"); if (handle_handshake(ctrl_vchan) < 0) exit(1); old_umask = umask(0); trigger_fd = get_server_socket(QREXEC_AGENT_TRIGGER_PATH); umask(old_umask); register_exec_func(do_exec); /* wait for qrexec daemon */ while (!libvchan_is_open(ctrl_vchan)) libvchan_wait(ctrl_vchan); }
/** may sleep (only if no data is available for reading); may return less data than requested; returns the amount of data processed, -1 on error or peer close */ int libvchan_read(struct libvchan *ctrl, char *data, int size) { int avail, avail_contig; int real_idx; while ((avail = libvchan_data_ready(ctrl)) == 0) if (libvchan_wait(ctrl) < 0) return -1; if (avail > size) avail = size; real_idx = (*ctrl->rd_cons) & (ctrl->rd_ring_size - 1); avail_contig = ctrl->rd_ring_size - real_idx; if (avail_contig < avail) avail = avail_contig; memcpy(data, ctrl->rd_ring + real_idx, avail); *ctrl->rd_cons += avail; if (do_notify(ctrl) < 0) return -1; return avail; }
/** 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; }
int wait_for_vchan_or_argfd_once(libvchan_t *vchan, int nfd, int *fd, fd_set * retset) { fd_set rfds; int vfd, max = 0, ret, i; struct timeval tv = { 0, 1000000 }; write_data(vchan, NULL, 0); // trigger write of queued data, if any present vfd = libvchan_fd_for_select(vchan); FD_ZERO(&rfds); for (i = 0; i < nfd; i++) { int cfd = fd[i]; FD_SET(cfd, &rfds); if (cfd > max) max = cfd; } FD_SET(vfd, &rfds); if (vfd > max) max = vfd; max++; ret = select(max, &rfds, NULL, NULL, &tv); if (ret < 0 && errno == EINTR) return -1; if (ret < 0) { perror("select"); exit(1); } if (!libvchan_is_open(vchan)) { fprintf(stderr, "libvchan_is_eof\n"); libvchan_close(vchan); if (vchan_at_eof != NULL) { vchan_at_eof(); return -1; } else exit(0); } if (FD_ISSET(vfd, &rfds)) // the following will never block; we need to do this to // clear libvchan_fd pending state libvchan_wait(vchan); if (retset) *retset = rfds; return ret; }
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"); }
int main(int argc, char **argv) { int opt; char *domname = NULL; libvchan_t *data_vchan = NULL; int data_port; int data_domain; int msg_type; int s; int just_exec = 0; int connect_existing = 0; char *local_cmdline = NULL; char *remote_cmdline = NULL; char *request_id; char *src_domain_name = NULL; int src_domain_id = 0; /* if not -c given, the process is run in dom0 */ struct service_params svc_params; while ((opt = getopt(argc, argv, "d:l:ec:tT")) != -1) { switch (opt) { case 'd': domname = strdup(optarg); break; case 'l': local_cmdline = strdup(optarg); break; case 'e': just_exec = 1; break; case 'c': parse_connect(optarg, &request_id, &src_domain_name, &src_domain_id); connect_existing = 1; is_service = 1; break; case 't': replace_esc_stdout = 1; break; case 'T': replace_esc_stderr = 1; break; default: usage(argv[0]); } } if (optind >= argc || !domname) usage(argv[0]); remote_cmdline = argv[optind]; register_exec_func(&do_exec); if (just_exec + connect_existing + (local_cmdline != 0) > 1) { fprintf(stderr, "ERROR: only one of -e, -l, -c can be specified\n"); usage(argv[0]); } if (strcmp(domname, "dom0") == 0 && !connect_existing) { fprintf(stderr, "ERROR: when target domain is 'dom0', -c must be specified\n"); usage(argv[0]); } if (strcmp(domname, "dom0") == 0) { if (connect_existing) { msg_type = MSG_SERVICE_CONNECT; strncpy(svc_params.ident, request_id, sizeof(svc_params.ident)); } else if (just_exec) msg_type = MSG_JUST_EXEC; else msg_type = MSG_EXEC_CMDLINE; assert(src_domain_name); setenv("QREXEC_REMOTE_DOMAIN", src_domain_name, 1); s = connect_unix_socket(src_domain_name); negotiate_connection_params(s, 0, /* dom0 */ msg_type, connect_existing ? (void*)&svc_params : (void*)remote_cmdline, connect_existing ? sizeof(svc_params) : strlen(remote_cmdline) + 1, &data_domain, &data_port); prepare_local_fds(remote_cmdline); if (connect_existing) data_vchan = libvchan_client_init(data_domain, data_port); else { data_vchan = libvchan_server_init(data_domain, data_port, VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE); while (data_vchan && libvchan_is_open(data_vchan) == VCHAN_WAITING) libvchan_wait(data_vchan); } if (!data_vchan || !libvchan_is_open(data_vchan)) { fprintf(stderr, "Failed to open data vchan connection\n"); do_exit(1); } if (handle_agent_handshake(data_vchan, connect_existing) < 0) do_exit(1); select_loop(data_vchan); } else { if (just_exec) msg_type = MSG_JUST_EXEC; else msg_type = MSG_EXEC_CMDLINE; s = connect_unix_socket(domname); negotiate_connection_params(s, src_domain_id, msg_type, remote_cmdline, strlen(remote_cmdline) + 1, &data_domain, &data_port); close(s); setenv("QREXEC_REMOTE_DOMAIN", domname, 1); prepare_local_fds(local_cmdline); if (connect_existing) { s = connect_unix_socket(src_domain_name); send_service_connect(s, request_id, data_domain, data_port); close(s); } else { data_vchan = libvchan_server_init(data_domain, data_port, VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE); if (!data_vchan) { fprintf(stderr, "Failed to start data vchan server\n"); do_exit(1); } while (libvchan_is_open(data_vchan) == VCHAN_WAITING) libvchan_wait(data_vchan); if (!libvchan_is_open(data_vchan)) { fprintf(stderr, "Failed to open data vchan connection\n"); do_exit(1); } if (handle_agent_handshake(data_vchan, 0) < 0) do_exit(1); select_loop(data_vchan); } } return 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); } }