static int _get_read_fd(XferElementGlue *self) { assert(self->read_fdp); if (self->read_fdp == &neighboring_element_fd) { XferElement *elt = XFER_ELEMENT(self); self->read_fd = xfer_element_swap_output_fd(elt->upstream, -1); } else { self->read_fd = *self->read_fdp; *self->read_fdp = -1; } self->read_fdp = NULL; return self->read_fd; }
/* create an element of this class; prototype is in xfer-element.h */ XferElement * xfer_source_fd( int fd) { XferSourceFd *self = (XferSourceFd *)g_object_new(XFER_SOURCE_FD_TYPE, NULL); XferElement *elt = XFER_ELEMENT(self); int old_fd; g_assert(fd >= 0); /* we read from a *copy* of this file descriptor, as the downstream element * will close output_fd on EOF */ old_fd = xfer_element_swap_output_fd(elt, dup(fd)); g_assert(old_fd == -1); return elt; }
static gboolean setup_impl( XferElement *elt) { XferElementGlue *self = (XferElementGlue *)elt; gboolean need_ring = FALSE; gboolean need_listen_input = FALSE; gboolean need_listen_output = FALSE; g_assert(elt->input_mech != XFER_MECH_NONE); g_assert(elt->output_mech != XFER_MECH_NONE); g_assert(elt->input_mech != elt->output_mech); self->read_fdp = NULL; self->write_fdp = NULL; self->on_push = PUSH_INVALID; self->on_pull = PULL_INVALID; self->need_thread = FALSE; switch (mech_pair(elt->input_mech, elt->output_mech)) { case mech_pair(XFER_MECH_READFD, XFER_MECH_WRITEFD): /* thread will read from one fd and write to the other */ self->read_fdp = &neighboring_element_fd; self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_PUSH_BUFFER): /* thread will read from one fd and call push_buffer downstream */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_PULL_BUFFER): self->read_fdp = &neighboring_element_fd; self->on_pull = PULL_FROM_FD; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then read from fd and write to the * socket. */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_READFD, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept output conn, then read from upstream and write to socket */ self->read_fdp = &neighboring_element_fd; self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_READFD): make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_PUSH_BUFFER): /* thread will read from pipe and call downstream's push_buffer */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_PULL_BUFFER): make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->on_pull = PULL_FROM_FD; self->read_fdp = &self->pipe[0]; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then read from pipe and write to socket */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_WRITEFD, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept output conn, then read from pipe and write to socket */ make_pipe(self); g_assert(xfer_element_swap_input_fd(elt, self->pipe[1]) == -1); self->pipe[1] = -1; /* upstream will close this for us */ self->read_fdp = &self->pipe[0]; self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_READFD): make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->on_push = PUSH_TO_FD; self->write_fdp = &self->pipe[1]; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_WRITEFD): self->on_push = PUSH_TO_FD; self->write_fdp = &neighboring_element_fd; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_PULL_BUFFER): self->on_push = PUSH_TO_RING_BUFFER; self->on_pull = PULL_FROM_RING_BUFFER; need_ring = TRUE; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_DIRECTTCP_LISTEN): /* push will connect for output first */ self->on_push = PUSH_TO_FD | PUSH_CONNECT_FIRST; break; case mech_pair(XFER_MECH_PUSH_BUFFER, XFER_MECH_DIRECTTCP_CONNECT): /* push will accept for output first */ self->on_push = PUSH_TO_FD | PUSH_ACCEPT_FIRST; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_READFD): /* thread will pull from upstream and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_WRITEFD): /* thread will pull from upstream and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_PUSH_BUFFER): /* thread will pull from upstream and push to downstream */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect for output, then pull from upstream and write to socket */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_PULL_BUFFER, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept for output, then pull from upstream and write to socket */ self->need_thread = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_READFD): /* thread will accept for input, then read from socket and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_WRITEFD): /* thread will accept for input, then read from socket and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_PUSH_BUFFER): /* thread will accept for input, then read from socket and push downstream */ self->need_thread = TRUE; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_PULL_BUFFER): /* first pull will accept for input, then read from socket */ self->on_pull = PULL_FROM_FD | PULL_ACCEPT_FIRST; need_listen_input = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_LISTEN, XFER_MECH_DIRECTTCP_CONNECT): /* thread will accept on both sides, then copy from socket to socket */ self->need_thread = TRUE; need_listen_input = TRUE; need_listen_output = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_READFD): /* thread will connect for input, then read from socket and write to pipe */ make_pipe(self); g_assert(xfer_element_swap_output_fd(elt, self->pipe[0]) == -1); self->pipe[0] = -1; /* downstream will close this for us */ self->write_fdp = &self->pipe[1]; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_WRITEFD): /* thread will connect for input, then read from socket and write to downstream */ self->write_fdp = &neighboring_element_fd; self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_PUSH_BUFFER): /* thread will connect for input, then read from socket and push downstream */ self->need_thread = TRUE; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_PULL_BUFFER): /* first pull will connect for input, then read from socket */ self->on_pull = PULL_FROM_FD | PULL_CONNECT_FIRST; break; case mech_pair(XFER_MECH_DIRECTTCP_CONNECT, XFER_MECH_DIRECTTCP_LISTEN): /* thread will connect on both sides, then copy from socket to socket */ self->on_pull = PULL_FROM_FD | PULL_ACCEPT_FIRST; self->need_thread = TRUE; break; default: g_assert_not_reached(); break; } /* set up ring if desired */ if (need_ring) { self->ring = g_try_malloc(sizeof(*self->ring) * GLUE_RING_BUFFER_SIZE); if (self->ring == NULL) { xfer_cancel_with_error(elt, "Can't allocate memory for ring"); return FALSE; } self->ring_used_sem = amsemaphore_new_with_value(0); self->ring_free_sem = amsemaphore_new_with_value(GLUE_RING_BUFFER_SIZE); } if (need_listen_input) { if (!do_directtcp_listen(elt, &self->input_listen_socket, &elt->input_listen_addrs)) return FALSE; } if (need_listen_output) { if (!do_directtcp_listen(elt, &self->output_listen_socket, &elt->output_listen_addrs)) return FALSE; } return TRUE; }
static gboolean start_impl( XferElement *elt) { char *tmpbuf; XferFilterProcess *self = (XferFilterProcess *)elt; char *cmd_str; char **argv; char *errmsg; char **env; int rfd, wfd; /* first build up a log message of what we're going to do, properly shell quoted */ argv = self->argv; cmd_str = g_shell_quote(*(argv++)); while (*argv) { char *qarg = g_shell_quote(*(argv++)); tmpbuf = g_strconcat(cmd_str, " ", qarg, NULL); g_free(cmd_str); cmd_str = tmpbuf; g_free(qarg); } g_debug("%s spawning: %s", xfer_element_repr(elt), cmd_str); rfd = xfer_element_swap_output_fd(elt->upstream, -1); wfd = xfer_element_swap_input_fd(elt->downstream, -1); /* now fork off the child and connect the pipes */ switch (self->child_pid = fork()) { case -1: error("cannot fork: %s", strerror(errno)); /* NOTREACHED */ case 0: /* child */ /* first, copy our fd's out of the stdio range */ while (rfd >= 0 && rfd <= STDERR_FILENO) rfd = dup(rfd); while (wfd >= 0 && wfd <= STDERR_FILENO) wfd = dup(wfd); /* set up stdin, stdout, and stderr, overwriting anything already open * on those fd's */ if (rfd > 0) dup2(rfd, STDIN_FILENO); if (wfd > 0) dup2(wfd, STDOUT_FILENO); dup2(self->pipe_err[1], STDERR_FILENO); /* and close everything else */ safe_fd(-1, 0); env = safe_env(); if (self->need_root && !become_root()) { errmsg = g_strdup_printf("could not become root: %s\n", strerror(errno)); full_write(STDERR_FILENO, errmsg, strlen(errmsg)); exit(1); } execve(self->argv[0], self->argv, env); free_env(env); errmsg = g_strdup_printf("exec of '%s' failed: %s\n", self->argv[0], strerror(errno)); full_write(STDERR_FILENO, errmsg, strlen(errmsg)); exit(1); default: /* parent */ break; } g_free(cmd_str); /* close the pipe fd's */ close(rfd); close(wfd); close(self->pipe_err[1]); /* watch for child death */ self->child_watch = new_child_watch_source(self->child_pid); g_source_set_callback(self->child_watch, (GSourceFunc)child_watch_callback, self, NULL); g_source_attach(self->child_watch, NULL); g_source_unref(self->child_watch); return TRUE; }