From a1ec530945a871e5436365068ea191cd0f02258e Mon Sep 17 00:00:00 2001 From: Unbit Date: Thu, 26 Sep 2013 19:28:09 +0200 Subject: [PATCH] implemented uwsgi protocol for forkptyrouter --- plugins/forkptyrouter/forkptyrouter.c | 64 ++++++++++++++++++++++++++- plugins/pty/pty.c | 40 ++++++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/plugins/forkptyrouter/forkptyrouter.c b/plugins/forkptyrouter/forkptyrouter.c index 327fddf4..2b87712e 100644 --- a/plugins/forkptyrouter/forkptyrouter.c +++ b/plugins/forkptyrouter/forkptyrouter.c @@ -2,6 +2,13 @@ uWSGI forkpty-router + can use the uwsgi protocol, modifier2 means: + + 0 -> stdin + 1-99 -> UNIX signal + 100 -> window rows (pktsize is the window size) + 101 -> window cols (pktsize is the window size) + */ #include @@ -24,12 +31,16 @@ extern struct uwsgi_server uwsgi; static struct uwsgi_forkptyrouter { struct uwsgi_corerouter cr; char *cmd; + // use the uwsgi protocol ? + int uwsgi; } ufpty; extern struct uwsgi_server uwsgi; struct forkptyrouter_session { struct corerouter_session session; + size_t restore_size; + struct winsize w; pid_t pid; }; @@ -61,6 +72,7 @@ static struct uwsgi_option forkptyrouter_options[] = { // write to backend static ssize_t fpty_instance_write(struct corerouter_peer *peer) { + struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session; ssize_t len = cr_write(peer, "fpty_instance_write()"); // end on empty write if (!len) return 0; @@ -68,7 +80,8 @@ static ssize_t fpty_instance_write(struct corerouter_peer *peer) { // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the buffer - peer->out->pos = 0; + if (uwsgi_buffer_decapitate(peer->out, peer->out->pos)) return -1; + peer->out->pos = fpty_session->restore_size; cr_reset_hooks(peer); } @@ -91,6 +104,42 @@ static ssize_t fpty_write(struct corerouter_peer *main_peer) { return len; } +static ssize_t fpty_parse_uwsgi(struct corerouter_peer *peer) { + + struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session; + for(;;) { + if (peer->in->pos < 4) return 0; + struct uwsgi_header *uh = (struct uwsgi_header *) peer->in->buf; + uint16_t pktsize = uh->pktsize; + switch(uh->modifier2) { + case 0: + // stdin + if ((size_t) (pktsize+4) > peer->in->pos) return 0; + if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; + return pktsize; + case 100: + if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; + fpty_session->w.ws_row = pktsize; + ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w); + // rows + break; + case 101: + if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; + fpty_session->w.ws_col = pktsize; + ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w); + // cols + break; + default: + if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; + // send signal + kill(fpty_session->pid, uh->modifier2); + break; + } + } + + return 0; +} + // read from backend static ssize_t fpty_instance_read(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "fpty_instance_read()"); @@ -106,10 +155,18 @@ static ssize_t fpty_instance_read(struct corerouter_peer *peer) { // read from client static ssize_t fpty_read(struct corerouter_peer *main_peer) { + struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) main_peer->session; ssize_t len = cr_read(main_peer, "fpty_read()"); if (!len) return 0; + ssize_t rlen = fpty_parse_uwsgi(main_peer); + if (rlen < 0) return -1; + if (rlen == 0) return 1; + + fpty_session->restore_size = main_peer->in->pos - rlen; + main_peer->session->peers->out = main_peer->in; + main_peer->session->peers->out->pos = rlen; main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer->session->peers, fpty_instance_write); @@ -137,12 +194,15 @@ static int forkptyrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsg cs->close = fpty_session_close; struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs; + // default terminal size + fpty_session->w.ws_row = 24; + fpty_session->w.ws_col = 80; // add a new peer struct corerouter_peer *peer = uwsgi_cr_peer_add(cs); // on new connection generate a new pty - fpty_session->pid = forkpty(&peer->fd, NULL, NULL, NULL); + fpty_session->pid = forkpty(&peer->fd, NULL, NULL, &fpty_session->w); if (fpty_session->pid < 0) { uwsgi_error("forkpty()"); return -1; diff --git a/plugins/pty/pty.c b/plugins/pty/pty.c index db7710e1..ac5a409c 100644 --- a/plugins/pty/pty.c +++ b/plugins/pty/pty.c @@ -21,6 +21,7 @@ struct uwsgi_pty_client { static struct uwsgi_pty { char *addr; char *remote; + char *uremote; int queue; int server_fd; int master_fd; @@ -77,6 +78,7 @@ static struct uwsgi_option uwsgi_pty_options[] = { {"pty-log", no_argument, 0, "send stdout/stderr to the log engine too", uwsgi_opt_true, &upty.log, 0}, {"pty-input", no_argument, 0, "read from original stdin in addition to pty", uwsgi_opt_true, &upty.input, 0}, {"pty-connect", required_argument, 0, "connect the current terminal to a pty server", uwsgi_opt_set_str, &upty.remote, 0}, + {"pty-uconnect", required_argument, 0, "connect the current terminal to a pty server (using uwsgi protocol)", uwsgi_opt_set_str, &upty.uremote, 0}, {"pty-no-isig", no_argument, 0, "disable ISIG terminal attribute in client mode", uwsgi_opt_true, &upty.no_isig, 0}, {"pty-exec", required_argument, 0, "run the specified command soon after the pty thread is spawned", uwsgi_opt_set_str, &upty.command, 0}, {0, 0, 0, 0, 0, 0, 0}, @@ -256,6 +258,27 @@ static void uwsgi_pty_init() { } +static void uwsgi_pty_winch() { + // 2 uwsgi packets + char uwsgi_pkt[8]; +#ifdef TIOCGWINSZ + struct winsize w; + ioctl(0, TIOCGWINSZ, &w); + uwsgi_pkt[0] = 0; + uwsgi_pkt[1] = (uint8_t) (w.ws_row & 0xff); + uwsgi_pkt[2] = (uint8_t) ((w.ws_row >> 8) & 0xff); + uwsgi_pkt[3] = 100; + uwsgi_pkt[4] = 0; + uwsgi_pkt[5] = (uint8_t) (w.ws_col & 0xff); + uwsgi_pkt[6] = (uint8_t) ((w.ws_col >> 8) & 0xff); + uwsgi_pkt[7] = 101; +#endif + if (write(upty.server_fd, uwsgi_pkt, 8) != 8) { + uwsgi_error("uwsgi_pty_winch()/write()"); + exit(1); + } +} + static int uwsgi_pty_client() { if (!upty.remote) return 0; @@ -277,8 +300,14 @@ static int uwsgi_pty_client() { uwsgi_log("[pty] connected.\n"); + uwsgi_pty_setterm(0); + signal(SIGWINCH, uwsgi_pty_winch); + + // send current terminal size + uwsgi_pty_winch(); + upty.queue = event_queue_init(); event_queue_add_fd_read(upty.queue, upty.server_fd); event_queue_add_fd_read(upty.queue, 0); @@ -287,10 +316,19 @@ static int uwsgi_pty_client() { char buf[8192]; int interesting_fd = -1; int ret = event_queue_wait(upty.queue, -1, &interesting_fd); - if (ret <= 0) break; + if (ret == 0) break; + if (ret < 0) { + if (errno == EINTR) continue; + break; + } if (interesting_fd == 0) { ssize_t rlen = read(0, buf, 8192); if (rlen <= 0) break; + struct uwsgi_header uh; + uh.modifier1 = 0; + uh.pktsize = rlen; + uh.modifier2 = 0; + if (write(upty.server_fd, &uh, 4) != 4) break; if (write(upty.server_fd, buf, rlen) != rlen) break; continue; }