From a8c3df9c80dadaa15c6a29894d3ab1fd3902e91a Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Mon, 16 Apr 2012 06:22:35 -0400 Subject: [PATCH] More robust shutdown sequence with warning on unclean shutdown. --- src/frontend/stmclient.cc | 22 ++++++++++++++-------- src/frontend/stmclient.h | 6 +++++- src/frontend/terminaloverlay.h | 2 +- src/network/transportsender.cc | 8 +++++--- src/network/transportsender.h | 2 +- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/frontend/stmclient.cc b/src/frontend/stmclient.cc index 672d3a3..e414c8a 100644 --- a/src/frontend/stmclient.cc +++ b/src/frontend/stmclient.cc @@ -87,6 +87,10 @@ void STMClient::init( void ) if ( !getenv( "MOSH_TITLE_NOPREFIX" ) ) { overlays.set_title_prefix( wstring( L"[mosh] " ) ); } + + wchar_t tmp[ 128 ]; + swprintf( tmp, 128, L"Nothing received from server on UDP port %d.", port ); + connecting_notification = wstring( tmp ); } void STMClient::shutdown( void ) @@ -109,6 +113,10 @@ void STMClient::shutdown( void ) fprintf( stderr, "mosh did not make a successful connection to %s:%d.\n", ip.c_str(), port ); fprintf( stderr, "Please verify that UDP port %d is not firewalled and can reach the server.\n\n", port ); fprintf( stderr, "(By default, mosh uses a UDP port between 60000 and 61000. The -p option\nselects a specific UDP port number.)\n" ); + } else if ( network ) { + if ( !clean_shutdown ) { + fprintf( stderr, "\n\nmosh did not shut down cleanly. Please note that the\nmosh-server process may still be running on the server.\n" ); + } } } @@ -223,7 +231,7 @@ bool STMClient::process_user_input( int fd ) if ( quit_sequence_started ) { if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */ if ( network->has_remote_addr() && (!network->shutdown_in_progress()) ) { - overlays.get_notification_engine().set_notification_string( wstring( L"Exiting on user request..." ) ); + overlays.get_notification_engine().set_notification_string( wstring( L"Exiting on user request..." ), true ); network->start_shutdown(); return true; } else { @@ -328,7 +336,7 @@ void STMClient::main( void ) if ( !network->has_remote_addr() ) { break; } else if ( !network->shutdown_in_progress() ) { - overlays.get_notification_engine().set_notification_string( wstring( L"Exiting..." ) ); + overlays.get_notification_engine().set_notification_string( wstring( L"Exiting..." ), true ); network->start_shutdown(); } } @@ -346,7 +354,7 @@ void STMClient::main( void ) if ( !network->has_remote_addr() ) { break; } else if ( !network->shutdown_in_progress() ) { - overlays.get_notification_engine().set_notification_string( wstring( L"Signal received, shutting down..." ) ); + overlays.get_notification_engine().set_notification_string( wstring( L"Signal received, shutting down..." ), true ); network->start_shutdown(); } } @@ -364,13 +372,14 @@ void STMClient::main( void ) if ( !network->has_remote_addr() ) { break; } else if ( !network->shutdown_in_progress() ) { - overlays.get_notification_engine().set_notification_string( wstring( L"Exiting..." ) ); + overlays.get_notification_engine().set_notification_string( wstring( L"Exiting..." ), true ); network->start_shutdown(); } } /* quit if our shutdown has been acknowledged */ if ( network->shutdown_in_progress() && network->shutdown_acknowledged() ) { + clean_shutdown = true; break; } @@ -381,14 +390,11 @@ void STMClient::main( void ) /* quit if we received and acknowledged a shutdown request */ if ( network->counterparty_shutdown_ack_sent() ) { + clean_shutdown = true; break; } /* write diagnostic message if can't reach server */ - wchar_t tmp[ 128 ]; - swprintf( tmp, 128, L"Nothing received from server on UDP port %d.", port ); - wstring connecting_notification( tmp ); - if ( still_connecting() && (!network->shutdown_in_progress()) && (timestamp() - network->get_latest_remote_state().timestamp > 250) ) { diff --git a/src/frontend/stmclient.h b/src/frontend/stmclient.h index f97a1fb..b878dcd 100644 --- a/src/frontend/stmclient.h +++ b/src/frontend/stmclient.h @@ -44,7 +44,9 @@ private: Network::Transport< Network::UserStream, Terminal::Complete > *network; Terminal::Display display; + std::wstring connecting_notification; bool repaint_requested, quit_sequence_started; + bool clean_shutdown; void main_init( void ); bool process_network_input( void ); @@ -70,8 +72,10 @@ public: overlays(), network( NULL ), display( true ), /* use TERM environment var to initialize display */ + connecting_notification(), repaint_requested( false ), - quit_sequence_started( false ) + quit_sequence_started( false ), + clean_shutdown( false ) { if ( predict_mode ) { if ( !strcmp( predict_mode, "always" ) ) { diff --git a/src/frontend/terminaloverlay.h b/src/frontend/terminaloverlay.h index d4bde26..99a1429 100644 --- a/src/frontend/terminaloverlay.h +++ b/src/frontend/terminaloverlay.h @@ -134,7 +134,7 @@ namespace Overlay { bool need_countup( uint64_t ts ) const { return ts - last_word_from_server > 6500; } void adjust_message( void ); void apply( Framebuffer &fb ) const; - void set_notification_string( const wstring s_message ) { message = s_message; message_expiration = timestamp() + 1000; } + void set_notification_string( const wstring &s_message, bool permanent = false ) { message = s_message; if ( permanent ) { message_expiration = -1; } else { message_expiration = timestamp() + 1000; } } const wstring &get_notification_string( void ) const { return message; } void server_heard( uint64_t s_last_word ) { last_word_from_server = s_last_word; } uint64_t get_message_expiration( void ) const { return message_expiration; } diff --git a/src/network/transportsender.cc b/src/network/transportsender.cc index eac3b99..6beb797 100644 --- a/src/network/transportsender.cc +++ b/src/network/transportsender.cc @@ -159,7 +159,9 @@ void TransportSender::tick( void ) template void TransportSender::send_empty_ack( void ) { - assert ( timestamp() >= next_ack_time ); + uint64_t now = timestamp(); + + assert( now >= next_ack_time ); uint64_t new_num = sent_states.back().num + 1; @@ -169,10 +171,10 @@ void TransportSender::send_empty_ack( void ) } // sent_states.push_back( TimestampedState( sent_states.back().timestamp, new_num, current_state ) ); - add_sent_state( sent_states.back().timestamp, new_num, current_state ); + add_sent_state( now, new_num, current_state ); send_in_fragments( "", new_num ); - next_ack_time = timestamp() + ACK_INTERVAL; + next_ack_time = now + ACK_INTERVAL; next_send_time = uint64_t(-1); } diff --git a/src/network/transportsender.h b/src/network/transportsender.h index d32af06..3de5fa2 100644 --- a/src/network/transportsender.h +++ b/src/network/transportsender.h @@ -43,7 +43,7 @@ namespace Network { static const int SEND_INTERVAL_MAX = 250; /* ms between frames */ static const int ACK_INTERVAL = 3000; /* ms between empty acks */ static const int ACK_DELAY = 100; /* ms before delayed ack */ - static const int SHUTDOWN_RETRIES = 3; /* number of shutdown packets to send before giving up */ + static const int SHUTDOWN_RETRIES = 16; /* number of shutdown packets to send before giving up */ static const int ACTIVE_RETRY_TIMEOUT = 10000; /* attempt to resend at frame rate */ /* helper methods for tick() */