static void sk_localproxy_close (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; del234(localproxy_by_fromfd, ps); del234(localproxy_by_tofd, ps); uxsel_del(ps->to_cmd); uxsel_del(ps->from_cmd); close(ps->to_cmd); close(ps->from_cmd); sfree(ps); }
static int agent_select_result(int fd, int event) { int ret; struct agent_connection *conn; assert(event == 1); /* not selecting for anything but R */ conn = find234(agent_connections, &fd, agent_connfind); if (!conn) { uxsel_del(fd); return 1; } ret = read(fd, conn->retbuf+conn->retlen, conn->retsize-conn->retlen); if (ret <= 0) { if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf); conn->retbuf = NULL; conn->retlen = 0; goto done; } conn->retlen += ret; if (conn->retsize == 4 && conn->retlen == 4) { conn->retsize = GET_32BIT(conn->retbuf); if (conn->retsize <= 0) { conn->retbuf = NULL; conn->retlen = 0; goto done; } conn->retsize += 4; assert(conn->retbuf == conn->sizebuf); conn->retbuf = snewn(conn->retsize, char); memcpy(conn->retbuf, conn->sizebuf, 4); }
static int localproxy_try_send(Local_Proxy_Socket ps) { int sent = 0; while (bufchain_size(&ps->pending_output_data) > 0) { void *data; int len, ret; bufchain_prefix(&ps->pending_output_data, &data, &len); ret = write(ps->to_cmd, data, len); if (ret < 0 && errno != EWOULDBLOCK) { /* We're inside the Unix frontend here, so we know * that the frontend handle is unnecessary. */ logevent(NULL, strerror(errno)); fatalbox("%s", strerror(errno)); } else if (ret <= 0) { break; } else { bufchain_consume(&ps->pending_output_data, ret); sent += ret; } } if (bufchain_size(&ps->pending_output_data) == 0) uxsel_del(ps->to_cmd); else uxsel_set(ps->to_cmd, 2, localproxy_select_result); return sent; }
static void sk_localproxy_set_frozen (Socket s, int is_frozen) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; if (is_frozen) uxsel_del(ps->from_cmd); else uxsel_set(ps->from_cmd, 1, localproxy_select_result); }
static void sk_localproxy_close (Socket s) { Local_Proxy_Socket ps = (Local_Proxy_Socket) s; if (ps->to_cmd >= 0) { del234(localproxy_by_tofd, ps); uxsel_del(ps->to_cmd); close(ps->to_cmd); } del234(localproxy_by_fromfd, ps); uxsel_del(ps->from_cmd); close(ps->from_cmd); bufchain_clear(&ps->pending_input_data); bufchain_clear(&ps->pending_output_data); sfree(ps); }
void uxsel_set(int fd, int rwx, uxsel_callback_fn callback) { struct fd *newfd; uxsel_del(fd); if (rwx) { newfd = snew(struct fd); newfd->fd = fd; newfd->rwx = rwx; newfd->callback = callback; newfd->id = uxsel_input_add(fd, rwx); add234(fds, newfd); } }
static int localproxy_try_send(Local_Proxy_Socket ps) { int sent = 0; while (bufchain_size(&ps->pending_output_data) > 0) { void *data; int len, ret; bufchain_prefix(&ps->pending_output_data, &data, &len); ret = write(ps->to_cmd, data, len); if (ret < 0 && errno != EWOULDBLOCK) { plug_closing(ps->plug, strerror(errno), errno, 0); return 0; } else if (ret <= 0) { break; } else { bufchain_consume(&ps->pending_output_data, ret); sent += ret; } } if (ps->outgoingeof == EOF_PENDING) { del234(localproxy_by_tofd, ps); close(ps->to_cmd); uxsel_del(ps->to_cmd); ps->to_cmd = -1; ps->outgoingeof = EOF_SENT; } if (bufchain_size(&ps->pending_output_data) == 0) uxsel_del(ps->to_cmd); else uxsel_set(ps->to_cmd, 2, localproxy_select_result); return sent; }
int pty_real_select_result(Pty pty, int event, int status) { char buf[4096]; int ret; int finished = FALSE; if (event < 0) { /* * We've been called because our child process did * something. `status' tells us what. */ if ((WIFEXITED(status) || WIFSIGNALED(status))) { /* * The primary child process died. We could keep * the terminal open for remaining subprocesses to * output to, but conventional wisdom seems to feel * that that's the Wrong Thing for an xterm-alike, * so we bail out now (though we don't necessarily * _close_ the window, depending on the state of * Close On Exit). This would be easy enough to * change or make configurable if necessary. */ pty->exit_code = status; pty->child_dead = TRUE; del234(ptys_by_pid, pty); finished = TRUE; } } else { if (event == 1) { ret = read(pty->master_fd, buf, sizeof(buf)); /* * Clean termination condition is that either ret == 0, or ret * < 0 and errno == EIO. Not sure why the latter, but it seems * to happen. Boo. */ if (ret == 0 || (ret < 0 && errno == EIO)) { /* * We assume a clean exit if the pty has closed but the * actual child process hasn't. The only way I can * imagine this happening is if it detaches itself from * the pty and goes daemonic - in which case the * expected usage model would precisely _not_ be for * the pterm window to hang around! */ finished = TRUE; if (!pty->child_dead) pty->exit_code = 0; } else if (ret < 0) { perror("read pty master"); exit(1); } else if (ret > 0) { from_backend(pty->frontend, 0, buf, ret); } } else if (event == 2) { /* * Attempt to send data down the pty. */ pty_try_write(pty); } } if (finished && !pty->finished) { int close_on_exit; uxsel_del(pty->master_fd); pty_close(pty); pty->master_fd = -1; pty->finished = TRUE; /* * This is a slight layering-violation sort of hack: only * if we're not closing on exit (COE is set to Never, or to * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ close_on_exit = conf_get_int(pty->conf, CONF_close_on_exit); if (close_on_exit == FORCE_OFF || (close_on_exit == AUTO && pty->exit_code != 0)) { char message[512]; message[0] = '\0'; if (WIFEXITED(pty->exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" " code %d]\r\n", WEXITSTATUS(pty->exit_code)); else if (WIFSIGNALED(pty->exit_code)) #ifdef HAVE_NO_STRSIGNAL sprintf(message, "\r\n[pterm: process terminated on signal" " %d]\r\n", WTERMSIG(pty->exit_code)); #else sprintf(message, "\r\n[pterm: process terminated on signal" " %d (%.400s)]\r\n", WTERMSIG(pty->exit_code), strsignal(WTERMSIG(pty->exit_code))); #endif from_backend(pty->frontend, 0, message, strlen(message)); } notify_remote_exit(pty->frontend); } return !finished; }
int pty_select_result(int fd, int event) { char buf[4096]; int ret; int finished = FALSE; if (fd == pty_master_fd && event == 1) { ret = read(pty_master_fd, buf, sizeof(buf)); /* * Clean termination condition is that either ret == 0, or ret * < 0 and errno == EIO. Not sure why the latter, but it seems * to happen. Boo. */ if (ret == 0 || (ret < 0 && errno == EIO)) { /* * We assume a clean exit if the pty has closed but the * actual child process hasn't. The only way I can * imagine this happening is if it detaches itself from * the pty and goes daemonic - in which case the * expected usage model would precisely _not_ be for * the pterm window to hang around! */ finished = TRUE; if (!pty_child_dead) pty_exit_code = 0; } else if (ret < 0) { perror("read pty master"); exit(1); } else if (ret > 0) { from_backend(pty_frontend, 0, buf, ret); } } else if (fd == pty_signal_pipe[0]) { pid_t pid; int status; char c[1]; read(pty_signal_pipe[0], c, 1); /* ignore its value; it'll be `x' */ do { pid = waitpid(-1, &status, WNOHANG); if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status))) { /* * The primary child process died. We could keep * the terminal open for remaining subprocesses to * output to, but conventional wisdom seems to feel * that that's the Wrong Thing for an xterm-alike, * so we bail out now (though we don't necessarily * _close_ the window, depending on the state of * Close On Exit). This would be easy enough to * change or make configurable if necessary. */ pty_exit_code = status; pty_child_dead = TRUE; finished = TRUE; } } while(pid > 0); } if (finished && !pty_finished) { uxsel_del(pty_master_fd); pty_close(); pty_master_fd = -1; pty_finished = TRUE; /* * This is a slight layering-violation sort of hack: only * if we're not closing on exit (COE is set to Never, or to * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ if (pty_cfg.close_on_exit == FORCE_OFF || (pty_cfg.close_on_exit == AUTO && pty_exit_code != 0)) { char message[512]; if (WIFEXITED(pty_exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" " code %d]\r\n", WEXITSTATUS(pty_exit_code)); else if (WIFSIGNALED(pty_exit_code)) #ifdef HAVE_NO_STRSIGNAL sprintf(message, "\r\n[pterm: process terminated on signal" " %d]\r\n", WTERMSIG(pty_exit_code)); #else sprintf(message, "\r\n[pterm: process terminated on signal" " %d (%.400s)]\r\n", WTERMSIG(pty_exit_code), strsignal(WTERMSIG(pty_exit_code))); #endif from_backend(pty_frontend, 0, message, strlen(message)); } } return !finished; }