summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
e12d95a)
to see the server slam the TCP connection shut (i.e. almost never,
unless it's just sent us an SSH_MSG_DISCONNECT), and treat an
unexpected closure as a non-clean session termination. Previously
any server-initiated connection closure was being treated as a clean
exit, which was a hangover from the good old Telnet-only days.
git-svn-id: svn://svn.tartarus.org/sgt/putty@5098
cda61777-01e9-0310-a592-
d414129be87e
static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
static int ssh_sendbuffer(void *handle);
static void ssh_throttle_all(Ssh ssh, int enable, int bufsize);
static void ssh2_set_window(struct ssh_channel *c, unsigned newwin);
static int ssh_sendbuffer(void *handle);
-static void ssh_do_close(Ssh ssh);
+static int ssh_do_close(Ssh ssh, int notify_exit);
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
static int ssh2_pkt_getbool(struct Packet *pkt);
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
static int ssh2_pkt_getbool(struct Packet *pkt);
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
tree234 *channels; /* indexed by local id */
struct ssh_channel *mainchan; /* primary session channel */
int exitcode;
tree234 *channels; /* indexed by local id */
struct ssh_channel *mainchan; /* primary session channel */
int exitcode;
tree234 *rportfwds, *portfwds;
tree234 *rportfwds, *portfwds;
#define bombout(msg) \
do { \
char *text = dupprintf msg; \
#define bombout(msg) \
do { \
char *text = dupprintf msg; \
+ ssh_do_close(ssh, FALSE); \
logevent(text); \
connection_fatal(ssh->frontend, "%s", text); \
sfree(text); \
logevent(text); \
connection_fatal(ssh->frontend, "%s", text); \
sfree(text); \
-static void ssh_do_close(Ssh ssh)
+static int ssh_do_close(Ssh ssh, int notify_exit)
struct ssh_channel *c;
ssh->state = SSH_STATE_CLOSED;
if (ssh->s) {
sk_close(ssh->s);
ssh->s = NULL;
struct ssh_channel *c;
ssh->state = SSH_STATE_CLOSED;
if (ssh->s) {
sk_close(ssh->s);
ssh->s = NULL;
- notify_remote_exit(ssh->frontend);
+ if (notify_exit)
+ notify_remote_exit(ssh->frontend);
+ else
+ ret = 1;
}
/*
* Now we must shut down any port and X forwardings going
}
/*
* Now we must shut down any port and X forwardings going
}
static int ssh_closing(Plug plug, const char *error_msg, int error_code,
int calling_back)
{
Ssh ssh = (Ssh) plug;
}
static int ssh_closing(Plug plug, const char *error_msg, int error_code,
int calling_back)
{
Ssh ssh = (Ssh) plug;
+ int need_notify = ssh_do_close(ssh, FALSE);
+
+ if (!error_msg && !ssh->close_expected) {
+ error_msg = "Server unexpectedly closed network connection";
+ }
+
if (error_msg) {
/* A socket error has occurred. */
logevent(error_msg);
connection_fatal(ssh->frontend, "%s", error_msg);
} else {
if (error_msg) {
/* A socket error has occurred. */
logevent(error_msg);
connection_fatal(ssh->frontend, "%s", error_msg);
} else {
- /* Otherwise, the remote side closed the connection normally. */
+ logevent("Server closed network connection");
+ if (need_notify)
+ notify_remote_exit(ssh->frontend);
Ssh ssh = (Ssh) plug;
ssh_gotdata(ssh, (unsigned char *)data, len);
if (ssh->state == SSH_STATE_CLOSED) {
Ssh ssh = (Ssh) plug;
ssh_gotdata(ssh, (unsigned char *)data, len);
if (ssh->state == SSH_STATE_CLOSED) {
+ ssh_do_close(ssh, TRUE);
* Terminate.
*/
logevent("No username provided. Abandoning session.");
* Terminate.
*/
logevent("No username provided. Abandoning session.");
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
crStop(1);
}
ssh_closing((Plug)ssh, NULL, 0, 0);
crStop(1);
}
PKT_END);
logevent("Unable to authenticate");
connection_fatal(ssh->frontend, "Unable to authenticate");
PKT_END);
logevent("Unable to authenticate");
connection_fatal(ssh->frontend, "Unable to authenticate");
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
crStop(1);
}
ssh_closing((Plug)ssh, NULL, 0, 0);
crStop(1);
}
* encrypted packet, we close the session once
* we've sent EXIT_CONFIRMATION.
*/
* encrypted packet, we close the session once
* we've sent EXIT_CONFIRMATION.
*/
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
}
ssh_closing((Plug)ssh, NULL, 0, 0);
}
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, s->pktout);
#endif
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, s->pktout);
#endif
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
}
}
ssh_closing((Plug)ssh, NULL, 0, 0);
}
}
ssh2_pkt_addstring(pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, pktout);
connection_fatal(ssh->frontend, "%s", buf);
ssh2_pkt_addstring(pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, pktout);
connection_fatal(ssh->frontend, "%s", buf);
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
return;
}
ssh_closing((Plug)ssh, NULL, 0, 0);
return;
}
* Terminate.
*/
logevent("No username provided. Abandoning session.");
* Terminate.
*/
logevent("No username provided. Abandoning session.");
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
logevent("Unable to authenticate");
connection_fatal(ssh->frontend,
"Unable to authenticate");
logevent("Unable to authenticate");
connection_fatal(ssh->frontend,
"Unable to authenticate");
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
" methods available");
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, s->pktout);
" methods available");
ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
ssh2_pkt_send_noqueue(ssh, s->pktout);
+ ssh->close_expected = TRUE;
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
ssh_closing((Plug)ssh, NULL, 0, 0);
crStopV;
}
ssh->kex_ctx = NULL;
ssh->hostkey = NULL;
ssh->exitcode = -1;
ssh->kex_ctx = NULL;
ssh->hostkey = NULL;
ssh->exitcode = -1;
+ ssh->close_expected = FALSE;
ssh->state = SSH_STATE_PREPACKET;
ssh->size_needed = FALSE;
ssh->eof_needed = FALSE;
ssh->state = SSH_STATE_PREPACKET;
ssh->size_needed = FALSE;
ssh->eof_needed = FALSE;
ssh->crcda_ctx = NULL;
}
if (ssh->s)
ssh->crcda_ctx = NULL;
}
if (ssh->s)
+ ssh_do_close(ssh, TRUE);
expire_timer_context(ssh);
if (ssh->pinger)
pinger_free(ssh->pinger);
expire_timer_context(ssh);
if (ssh->pinger)
pinger_free(ssh->pinger);