X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/bc06669bcf2c0d331e231d18c0e14023433f9e79..31393e34a75043e8b46834d284a08fc45402c707:/ssh.c diff --git a/ssh.c b/ssh.c index 291d58c4..7deb90c0 100644 --- a/ssh.c +++ b/ssh.c @@ -473,6 +473,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin); static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, struct Packet *pktin); +static void ssh2_channel_check_close(struct ssh_channel *c); static void ssh_channel_destroy(struct ssh_channel *c); /* @@ -849,6 +850,7 @@ struct ssh_tag { int size_needed, eof_needed; int sent_console_eof; + int got_pty; /* affects EOF behaviour on main channel */ struct Packet **queue; int queuelen, queuesize; @@ -5180,9 +5182,11 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, } else if (pktin->type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to allocate pty\r\n"); ssh->editing = ssh->echoing = 1; - } - logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", - ssh->ospeed, ssh->ispeed); + } else { + logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", + ssh->ospeed, ssh->ispeed); + ssh->got_pty = TRUE; + } } else { ssh->editing = ssh->echoing = 1; } @@ -6667,6 +6671,11 @@ static int ssh2_handle_winadj_response(struct ssh_channel *c) */ if (c->v.v2.throttle_state == UNTHROTTLING) c->v.v2.throttle_state = UNTHROTTLED; + /* + * We may now initiate channel-closing procedures, if that winadj + * was the last thing outstanding before we send CHANNEL_CLOSE. + */ + ssh2_channel_check_close(c); return TRUE; } @@ -6888,10 +6897,12 @@ static void ssh2_channel_check_close(struct ssh_channel *c) struct Packet *pktout; if ((c->closes & (CLOSES_SENT_EOF | CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE)) - == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF)) { + == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF) && !c->v.v2.winadj_head) { /* - * We have both sent and received EOF, which means the channel - * is in final wind-up. But we haven't sent CLOSE, so let's. + * We have both sent and received EOF, and we have no + * outstanding winadj channel requests, which means the + * channel is in final wind-up. But we haven't sent CLOSE, so + * let's do so now. */ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE); ssh2_pkt_adduint32(pktout, c->remoteid); @@ -6924,10 +6935,15 @@ static void ssh2_channel_got_eof(struct ssh_channel *c) } else if (c->type == CHAN_MAINSESSION) { Ssh ssh = c->ssh; - if (!ssh->sent_console_eof && from_backend_eof(ssh->frontend)) { + if (!ssh->sent_console_eof && + (from_backend_eof(ssh->frontend) || ssh->got_pty)) { /* - * The front end wants us to close the outgoing side of the - * connection as soon as we see EOF from the far end. + * Either from_backend_eof told us that the front end + * wants us to close the outgoing side of the connection + * as soon as we see EOF from the far end, or else we've + * unilaterally decided to do that because we've allocated + * a remote pty and hence EOF isn't a particularly + * meaningful concept. */ sshfwd_write_eof(c); } @@ -6962,6 +6978,36 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) ssh2_channel_got_eof(c); /* + * And we also send an outgoing EOF, if we haven't already, on the + * assumption that CLOSE is a pretty forceful announcement that + * the remote side is doing away with the entire channel. (If it + * had wanted to send us EOF and continue receiving data from us, + * it would have just sent CHANNEL_EOF.) + */ + if (!(c->closes & CLOSES_SENT_EOF)) { + /* + * Make sure we don't read any more from whatever our local + * data source is for this channel. + */ + switch (c->type) { + case CHAN_MAINSESSION: + ssh->send_ok = 0; /* stop trying to read from stdin */ + break; + case CHAN_X11: + x11_override_throttle(c->u.x11.s, 1); + break; + case CHAN_SOCKDATA: + pfd_override_throttle(c->u.pfd.s, 1); + break; + } + + /* + * Send outgoing EOF. + */ + sshfwd_write_eof(ssh->mainchan); + } + + /* * Now process the actual close. */ if (!(c->closes & CLOSES_RCVD_CLOSE)) { @@ -9010,6 +9056,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } else { logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", ssh->ospeed, ssh->ispeed); + ssh->got_pty = TRUE; } } else { ssh->editing = ssh->echoing = 1; @@ -9437,6 +9484,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->frozen = FALSE; ssh->username = NULL; ssh->sent_console_eof = FALSE; + ssh->got_pty = FALSE; *backend_handle = ssh;