mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Introduce a function sshfwd_unclean_close(), supplied by ssh.c to
subsidiary network modules like portfwd.c. To be called when the subsidiary module experiences a socket error: it sends an emergency CHANNEL_CLOSE (not just outgoing CHANNEL_EOF), and immediately deletes the local side of the channel. (I've invented a new channel type in ssh.c called CHAN_ZOMBIE, for channels whose original local side has already been thrown away and they're just hanging around waiting to receive the acknowledging CHANNEL_CLOSE.) As a result of this and the last few commits, I can now run a port forwarding session in which a local socket error occurs on a forwarded port, and PuTTY now handles it apparently correctly, closing both the SSH channel and the local socket and then actually recognising that it's OK to terminate when all _other_ channels have been closed. Previously the channel corresponding to the duff connection would linger around (because of net_pending_errors never being called), and keep being selected on (hence chewing CPU), and inhibit program termination at the end of the session (because not all channels were closed). [originally from svn r9364]
This commit is contained in:
parent
f892af999e
commit
49927f6c4d
24
portfwd.c
24
portfwd.c
@ -61,17 +61,19 @@ static int pfd_closing(Plug plug, const char *error_msg, int error_code,
|
|||||||
{
|
{
|
||||||
struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
|
struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
|
||||||
|
|
||||||
/*
|
if (error_msg) {
|
||||||
* We have no way to communicate down the forwarded connection,
|
/*
|
||||||
* so if an error occurred on the socket, we just ignore it
|
* Socket error. Slam the connection instantly shut.
|
||||||
* and treat it like a proper close.
|
*/
|
||||||
*
|
sshfwd_unclean_close(pr->c);
|
||||||
* FIXME: except we could initiate a full close here instead of
|
} else {
|
||||||
* just an outgoing EOF? ssh.c currently has no API for that, but
|
/*
|
||||||
* it could.
|
* Ordinary EOF received on socket. Send an EOF on the SSH
|
||||||
*/
|
* channel.
|
||||||
if (pr->c)
|
*/
|
||||||
sshfwd_write_eof(pr->c);
|
if (pr->c)
|
||||||
|
sshfwd_write_eof(pr->c);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
38
ssh.c
38
ssh.c
@ -558,7 +558,15 @@ enum { /* channel types */
|
|||||||
CHAN_X11,
|
CHAN_X11,
|
||||||
CHAN_AGENT,
|
CHAN_AGENT,
|
||||||
CHAN_SOCKDATA,
|
CHAN_SOCKDATA,
|
||||||
CHAN_SOCKDATA_DORMANT /* one the remote hasn't confirmed */
|
CHAN_SOCKDATA_DORMANT, /* one the remote hasn't confirmed */
|
||||||
|
/*
|
||||||
|
* CHAN_ZOMBIE is used to indicate a channel for which we've
|
||||||
|
* already destroyed the local data source: for instance, if a
|
||||||
|
* forwarded port experiences a socket error on the local side, we
|
||||||
|
* immediately destroy its local socket and turn the SSH channel
|
||||||
|
* into CHAN_ZOMBIE.
|
||||||
|
*/
|
||||||
|
CHAN_ZOMBIE
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4250,6 +4258,34 @@ void sshfwd_write_eof(struct ssh_channel *c)
|
|||||||
ssh_channel_try_eof(c);
|
ssh_channel_try_eof(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sshfwd_unclean_close(struct ssh_channel *c)
|
||||||
|
{
|
||||||
|
Ssh ssh = c->ssh;
|
||||||
|
struct Packet *pktout;
|
||||||
|
|
||||||
|
if (ssh->state == SSH_STATE_CLOSED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c->closes & CLOSES_SENT_CLOSE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
|
||||||
|
ssh2_pkt_adduint32(pktout, c->remoteid);
|
||||||
|
ssh2_pkt_send(ssh, pktout);
|
||||||
|
c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE;
|
||||||
|
switch (c->type) {
|
||||||
|
case CHAN_X11:
|
||||||
|
x11_close(c->u.x11.s);
|
||||||
|
break;
|
||||||
|
case CHAN_SOCKDATA:
|
||||||
|
case CHAN_SOCKDATA_DORMANT:
|
||||||
|
pfd_close(c->u.pfd.s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c->type = CHAN_ZOMBIE;
|
||||||
|
ssh2_channel_check_close(c);
|
||||||
|
}
|
||||||
|
|
||||||
int sshfwd_write(struct ssh_channel *c, char *buf, int len)
|
int sshfwd_write(struct ssh_channel *c, char *buf, int len)
|
||||||
{
|
{
|
||||||
Ssh ssh = c->ssh;
|
Ssh ssh = c->ssh;
|
||||||
|
1
ssh.h
1
ssh.h
@ -11,6 +11,7 @@ struct ssh_channel;
|
|||||||
|
|
||||||
extern int sshfwd_write(struct ssh_channel *c, char *, int);
|
extern int sshfwd_write(struct ssh_channel *c, char *, int);
|
||||||
extern void sshfwd_write_eof(struct ssh_channel *c);
|
extern void sshfwd_write_eof(struct ssh_channel *c);
|
||||||
|
extern void sshfwd_unclean_close(struct ssh_channel *c);
|
||||||
extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
|
extern void sshfwd_unthrottle(struct ssh_channel *c, int bufsize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user