From 0553aec60a0a7fdc01584db2df3e4b59925620d4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 22 May 2021 12:47:51 +0100 Subject: [PATCH] New Seat method, notify_remote_disconnect. This notifies the Seat that the entire backend session has finished and closed its network connection - or rather, that it _might_ have done, and that the frontend should check backend_connected() if it wasn't planning to do so already. The existing Seat implementations haven't needed this: the GUI ones don't actually need to do anything specific when the network connection goes away, and the CLI ones deal with it by being in charge of their own event loop so that they can easily check backend_connected() at every possible opportunity in any case. But I'm about to introduce a new Seat implementation that does need to know this, and doesn't have any other way to get notified of it. --- otherbackends/raw.c | 2 ++ otherbackends/rlogin.c | 1 + otherbackends/supdup.c | 1 + otherbackends/telnet.c | 1 + pscp.c | 1 + psftp.c | 1 + putty.h | 26 ++++++++++++++++++++++++++ ssh/server.c | 1 + ssh/sesschan.c | 1 + ssh/ssh.c | 3 +++ unix/plink.c | 1 + unix/window.c | 1 + utils/nullseat.c | 1 + windows/plink.c | 1 + windows/window.c | 1 + 15 files changed, 43 insertions(+) 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,