diff --git a/otherbackends/raw.c b/otherbackends/raw.c index 0c454985..7977f386 100644 --- a/otherbackends/raw.c +++ b/otherbackends/raw.c @@ -52,6 +52,7 @@ static void raw_check_close(Raw *raw) sk_close(raw->s); raw->s = NULL; seat_notify_remote_exit(raw->seat); + seat_notify_remote_disconnect(raw->seat); } } } @@ -68,6 +69,7 @@ static void raw_closing(Plug *plug, const char *error_msg, int error_code, raw->s = NULL; raw->closed_on_socket_error = true; seat_notify_remote_exit(raw->seat); + seat_notify_remote_disconnect(raw->seat); } logevent(raw->logctx, error_msg); seat_connection_fatal(raw->seat, "%s", error_msg); diff --git a/otherbackends/rlogin.c b/otherbackends/rlogin.c index 2a3714e0..8289a508 100644 --- a/otherbackends/rlogin.c +++ b/otherbackends/rlogin.c @@ -63,6 +63,7 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code, if (error_msg) rlogin->closed_on_socket_error = true; seat_notify_remote_exit(rlogin->seat); + seat_notify_remote_disconnect(rlogin->seat); } if (error_msg) { /* A socket error has occurred. */ diff --git a/otherbackends/supdup.c b/otherbackends/supdup.c index f210ebe3..36dbb447 100644 --- a/otherbackends/supdup.c +++ b/otherbackends/supdup.c @@ -581,6 +581,7 @@ static void supdup_closing(Plug *plug, const char *error_msg, int error_code, if (error_msg) supdup->closed_on_socket_error = true; seat_notify_remote_exit(supdup->seat); + seat_notify_remote_disconnect(supdup->seat); } if (error_msg) { logevent(supdup->logctx, error_msg); diff --git a/otherbackends/telnet.c b/otherbackends/telnet.c index 3a60e646..f8b41ac3 100644 --- a/otherbackends/telnet.c +++ b/otherbackends/telnet.c @@ -639,6 +639,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code, if (error_msg) telnet->closed_on_socket_error = true; seat_notify_remote_exit(telnet->seat); + seat_notify_remote_disconnect(telnet->seat); } if (error_msg) { logevent(telnet->logctx, error_msg); diff --git a/pscp.c b/pscp.c index 19bc3807..9accdf70 100644 --- a/pscp.c +++ b/pscp.c @@ -67,6 +67,7 @@ static const SeatVtable pscp_seat_vt = { .eof = pscp_eof, .get_userpass_input = filexfer_get_userpass_input, .notify_remote_exit = nullseat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = console_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, diff --git a/psftp.c b/psftp.c index c2791e3b..fd9b78d3 100644 --- a/psftp.c +++ b/psftp.c @@ -49,6 +49,7 @@ static const SeatVtable psftp_seat_vt = { .eof = psftp_eof, .get_userpass_input = filexfer_get_userpass_input, .notify_remote_exit = nullseat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = console_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, diff --git a/putty.h b/putty.h index a6d81b18..75dd5a86 100644 --- a/putty.h +++ b/putty.h @@ -924,6 +924,29 @@ struct SeatVtable { */ void (*notify_remote_exit)(Seat *seat); + /* + * Notify the seat that the whole connection has finished. + * (Distinct from notify_remote_exit, e.g. in the case where you + * have port forwardings still active when the main foreground + * session goes away: then you'd get notify_remote_exit when the + * foreground session dies, but notify_remote_disconnect when the + * last forwarding vanishes and the network connection actually + * closes.) + * + * This function might be called multiple times by accident; seats + * should be prepared to cope. + * + * More precisely: this function notifies the seat that + * backend_connected() might now return false where previously it + * returned true. (Note the 'might': an accidental duplicate call + * might happen when backend_connected() was already returning + * false. Or even, in weird situations, when it hadn't stopped + * returning true yet. The point is, when you get this + * notification, all it's really telling you is that it's worth + * _checking_ backend_connected, if you weren't already.) + */ + void (*notify_remote_disconnect)(Seat *seat); + /* * Notify the seat that the connection has suffered a fatal error. */ @@ -1095,6 +1118,8 @@ static inline int seat_get_userpass_input( { return seat->vt->get_userpass_input(seat, p, input); } static inline void seat_notify_remote_exit(Seat *seat) { seat->vt->notify_remote_exit(seat); } +static inline void seat_notify_remote_disconnect(Seat *seat) +{ seat->vt->notify_remote_disconnect(seat); } static inline void seat_update_specials_menu(Seat *seat) { seat->vt->update_specials_menu(seat); } static inline char *seat_get_ttymode(Seat *seat, const char *mode) @@ -1163,6 +1188,7 @@ size_t nullseat_output( bool nullseat_eof(Seat *seat); int nullseat_get_userpass_input(Seat *seat, prompts_t *p, bufchain *input); void nullseat_notify_remote_exit(Seat *seat); +void nullseat_notify_remote_disconnect(Seat *seat); void nullseat_connection_fatal(Seat *seat, const char *message); void nullseat_update_specials_menu(Seat *seat); char *nullseat_get_ttymode(Seat *seat, const char *mode); diff --git a/ssh/server.c b/ssh/server.c index e3fc86fe..642d4ce0 100644 --- a/ssh/server.c +++ b/ssh/server.c @@ -109,6 +109,7 @@ static const SeatVtable server_seat_vt = { .eof = nullseat_eof, .get_userpass_input = nullseat_get_userpass_input, .notify_remote_exit = nullseat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = nullseat_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, diff --git a/ssh/sesschan.c b/ssh/sesschan.c index 4b204b29..f1bed6f2 100644 --- a/ssh/sesschan.c +++ b/ssh/sesschan.c @@ -188,6 +188,7 @@ static const SeatVtable sesschan_seat_vt = { .eof = sesschan_seat_eof, .get_userpass_input = nullseat_get_userpass_input, .notify_remote_exit = sesschan_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = sesschan_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, diff --git a/ssh/ssh.c b/ssh/ssh.c index 868533d2..efeb1f7e 100644 --- a/ssh/ssh.c +++ b/ssh/ssh.c @@ -387,6 +387,7 @@ static void ssh_bpp_output_raw_data_callback(void *vctx) if (ssh->pending_close) { sk_close(ssh->s); ssh->s = NULL; + seat_notify_remote_disconnect(ssh->seat); } } @@ -428,6 +429,7 @@ static void ssh_shutdown(Ssh *ssh) if (ssh->s) { sk_close(ssh->s); ssh->s = NULL; + seat_notify_remote_disconnect(ssh->seat); } bufchain_clear(&ssh->in_raw); @@ -788,6 +790,7 @@ static char *connect_to_host( if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; seat_notify_remote_exit(ssh->seat); + seat_notify_remote_disconnect(ssh->seat); return dupstr(err); } } diff --git a/unix/plink.c b/unix/plink.c index 3e2a9b6b..f2310fc5 100644 --- a/unix/plink.c +++ b/unix/plink.c @@ -391,6 +391,7 @@ static const SeatVtable plink_seat_vt = { .eof = plink_eof, .get_userpass_input = plink_get_userpass_input, .notify_remote_exit = nullseat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = console_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = plink_get_ttymode, diff --git a/unix/window.c b/unix/window.c index 16306023..f787fa9b 100644 --- a/unix/window.c +++ b/unix/window.c @@ -391,6 +391,7 @@ static const SeatVtable gtk_seat_vt = { .eof = gtk_seat_eof, .get_userpass_input = gtk_seat_get_userpass_input, .notify_remote_exit = gtk_seat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = gtk_seat_connection_fatal, .update_specials_menu = gtk_seat_update_specials_menu, .get_ttymode = gtk_seat_get_ttymode, diff --git a/utils/nullseat.c b/utils/nullseat.c index 01aaabea..9b69a07a 100644 --- a/utils/nullseat.c +++ b/utils/nullseat.c @@ -10,6 +10,7 @@ bool nullseat_eof(Seat *seat) { return true; } int nullseat_get_userpass_input( Seat *seat, prompts_t *p, bufchain *input) { return 0; } void nullseat_notify_remote_exit(Seat *seat) {} +void nullseat_notify_remote_disconnect(Seat *seat) {} void nullseat_connection_fatal(Seat *seat, const char *message) {} void nullseat_update_specials_menu(Seat *seat) {} char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; } diff --git a/windows/plink.c b/windows/plink.c index 3166178f..071e088d 100644 --- a/windows/plink.c +++ b/windows/plink.c @@ -85,6 +85,7 @@ static const SeatVtable plink_seat_vt = { .eof = plink_eof, .get_userpass_input = plink_get_userpass_input, .notify_remote_exit = nullseat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = console_connection_fatal, .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, diff --git a/windows/window.c b/windows/window.c index a10cb536..c644422c 100644 --- a/windows/window.c +++ b/windows/window.c @@ -332,6 +332,7 @@ static const SeatVtable win_seat_vt = { .eof = win_seat_eof, .get_userpass_input = win_seat_get_userpass_input, .notify_remote_exit = win_seat_notify_remote_exit, + .notify_remote_disconnect = nullseat_notify_remote_disconnect, .connection_fatal = win_seat_connection_fatal, .update_specials_menu = win_seat_update_specials_menu, .get_ttymode = win_seat_get_ttymode,