Changed my mind about the EOF policy in SSH mode: I think the SSH
[sgt/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 291d58c..a211213 100644 (file)
--- 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);
         }
@@ -9010,6 +9026,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 +9454,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;