Check-in [de1e102574]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Nearly forgot noting this down in the 'half-closed' bug entry: don't send CHANNEL_CLOSE until we have acks for all our winadj requests. Should work around https://bugzilla.mindrot.org/show_bug.cgi?id=1818 .
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: de1e102574ad7977774f9c495ed8b0daac64154f
User & Date: simon 2011-09-13 06:56:25.000
Context
2011-09-13
10:38
Changed my mind about the EOF policy in SSH mode: I think the SSH backend should unilaterally assume outgoing EOF when it sees incoming EOF, if and only if the main session channel is talking to a pty. (Because ptys don't have a strong concept of EOF in the first place, that seems like a sensible place to draw the line.) This fixes a bug introduced by today's revamp in which if you used Unix Plink to run a console session it would hang after you hit ^D - because the server had sent EOF, but it was waiting for a client-side EOF too. check-in: 3aaf9b7e0f user: simon tags: trunk
06:56
Nearly forgot noting this down in the 'half-closed' bug entry: don't send CHANNEL_CLOSE until we have acks for all our winadj requests. Should work around https://bugzilla.mindrot.org/show_bug.cgi?id=1818 . check-in: de1e102574 user: simon tags: trunk
06:44
Revamp of EOF handling in all network connections, pipes and other data channels. Should comprehensively fix 'half-closed', in principle, though it's a big and complicated change and so there's a good chance I've made at least one mistake somewhere. All connections should now be rigorous about propagating end-of-file (or end-of-data-stream, or socket shutdown, or whatever) independently in both directions, except in frontends with no mechanism for sending explicit EOF (e.g. interactive terminal windows) or backends which are basically always used for interactive sessions so it's unlikely that an application would be depending on independent EOF (telnet, rlogin). EOF should now never accidentally be sent while there's still buffered data to go out before it. (May help fix 'portfwd-corrupt', and also I noticed recently that the ssh main session channel can accidentally have MSG_EOF sent before the output bufchain is clear, leading to embarrassment when it subsequently does send the output). check-in: 0831792ea4 user: simon tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to ssh.c.
469
470
471
472
473
474
475

476
477
478
479
480
481
482
static int ssh2_pkt_construct(Ssh, struct Packet *);
static void ssh2_pkt_send(Ssh, struct Packet *);
static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);
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 ssh_channel_destroy(struct ssh_channel *c);

/*
 * Buffer management constants. There are several of these for
 * various different purposes:
 * 
 *  - SSH1_BUFFER_LIMIT is the amount of backlog that must build up







>







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
static int ssh2_pkt_construct(Ssh, struct Packet *);
static void ssh2_pkt_send(Ssh, struct Packet *);
static void ssh2_pkt_send_noqueue(Ssh, struct Packet *);
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);

/*
 * Buffer management constants. There are several of these for
 * various different purposes:
 * 
 *  - SSH1_BUFFER_LIMIT is the amount of backlog that must build up
6663
6664
6665
6666
6667
6668
6669





6670
6671
6672
6673
6674
6675
6676
    /*
     * winadj messages are only sent when the window is fully open, so
     * if we get an ack of one, we know any pending unthrottle is
     * complete.
     */
    if (c->v.v2.throttle_state == UNTHROTTLING)
	c->v.v2.throttle_state = UNTHROTTLED;





    return TRUE;
}

static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin)
{
    /*
     * This should never get called.  All channel requests are either







>
>
>
>
>







6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
    /*
     * winadj messages are only sent when the window is fully open, so
     * if we get an ack of one, we know any pending unthrottle is
     * complete.
     */
    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;
}

static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin)
{
    /*
     * This should never get called.  All channel requests are either
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893

6894

6895
6896
6897
6898
6899
6900
6901

static void ssh2_channel_check_close(struct ssh_channel *c)
{
    Ssh ssh = c->ssh;
    struct Packet *pktout;

    if ((c->closes & (CLOSES_SENT_EOF | CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))
        == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF)) {
        /*
         * 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.

         */
	pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
	ssh2_pkt_adduint32(pktout, c->remoteid);
	ssh2_pkt_send(ssh, pktout);
        c->closes |= CLOSES_SENT_CLOSE;
    }








|

|
>
|
>







6890
6891
6892
6893
6894
6895
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909

static void ssh2_channel_check_close(struct ssh_channel *c)
{
    Ssh ssh = c->ssh;
    struct Packet *pktout;

    if ((c->closes & (CLOSES_SENT_EOF | CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))
        == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF) && !c->v.v2.winadj_head) {
        /*
         * 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);
	ssh2_pkt_send(ssh, pktout);
        c->closes |= CLOSES_SENT_CLOSE;
    }