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).
git-svn-id: svn://svn.tartarus.org/sgt/putty@9364
cda61777-01e9-0310-a592-
d414129be87e
{
struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;
- /*
- * We have no way to communicate down the forwarded connection,
- * so if an error occurred on the socket, we just ignore it
- * and treat it like a proper close.
- *
- * FIXME: except we could initiate a full close here instead of
- * just an outgoing EOF? ssh.c currently has no API for that, but
- * it could.
- */
- if (pr->c)
- sshfwd_write_eof(pr->c);
+ if (error_msg) {
+ /*
+ * Socket error. Slam the connection instantly shut.
+ */
+ sshfwd_unclean_close(pr->c);
+ } else {
+ /*
+ * Ordinary EOF received on socket. Send an EOF on the SSH
+ * channel.
+ */
+ if (pr->c)
+ sshfwd_write_eof(pr->c);
+ }
return 1;
}
CHAN_X11,
CHAN_AGENT,
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
};
/*
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)
{
Ssh ssh = c->ssh;
extern int sshfwd_write(struct ssh_channel *c, char *, int);
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);
/*