diff options
Diffstat (limited to 'src/frontend/mosh-server.cc')
-rw-r--r-- | src/frontend/mosh-server.cc | 737 |
1 files changed, 369 insertions, 368 deletions
diff --git a/src/frontend/mosh-server.cc b/src/frontend/mosh-server.cc index e258d1c..5d22553 100644 --- a/src/frontend/mosh-server.cc +++ b/src/frontend/mosh-server.cc @@ -81,14 +81,13 @@ #endif #include "src/statesync/completeterminal.h" -#include "src/util/swrite.h" #include "src/statesync/user.h" #include "src/util/fatal_assert.h" #include "src/util/locale_utils.h" #include "src/util/pty_compat.h" #include "src/util/select.h" +#include "src/util/swrite.h" #include "src/util/timestamp.h" -#include "src/util/fatal_assert.h" #ifndef _PATH_BSHELL #define _PATH_BSHELL "/bin/sh" @@ -100,34 +99,40 @@ using ServerConnection = Network::Transport<Terminal::Complete, Network::UserStr static void serve( int host_fd, int pipe_fd, - Terminal::Complete &terminal, - ServerConnection &network, - long network_timeout, - long network_signaled_timeout ); - -static int run_server( const char *desired_ip, const char *desired_port, - const std::string &command_path, char *command_argv[], - const int colors, unsigned int verbose, bool with_motd ); - - -static void print_version( FILE *file ) + Terminal::Complete& terminal, + ServerConnection& network, + long network_timeout, + long network_signaled_timeout ); + +static int run_server( const char* desired_ip, + const char* desired_port, + const std::string& command_path, + char* command_argv[], + const int colors, + unsigned int verbose, + bool with_motd ); + +static void print_version( FILE* file ) { fputs( "mosh-server (" PACKAGE_STRING ") [build " BUILD_VERSION "]\n" - "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n" - "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n", file ); + "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n" + "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n", + file ); } -static void print_usage( FILE *stream, const char *argv0 ) +static void print_usage( FILE* stream, const char* argv0 ) { - fprintf( stream, "Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2]] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n", argv0 ); + fprintf( stream, + "Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2]] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n", + argv0 ); } -static bool print_motd( const char *filename ); +static bool print_motd( const char* filename ); static void chdir_homedir( void ); static bool motd_hushed( void ); -static void warn_unattached( const std::string & ignore_entry ); +static void warn_unattached( const std::string& ignore_entry ); /* Simple spinloop */ static void spin( void ) @@ -146,7 +151,7 @@ static void spin( void ) static std::string get_SSH_IP( void ) { - const char *SSH_CONNECTION = getenv( "SSH_CONNECTION" ); + const char* SSH_CONNECTION = getenv( "SSH_CONNECTION" ); if ( !SSH_CONNECTION ) { /* Older sshds don't set this */ fputs( "Warning: SSH_CONNECTION not found; binding to any interface.\n", stderr ); return std::string( "" ); @@ -170,7 +175,7 @@ static std::string get_SSH_IP( void ) return local_interface_IP; } -int main( int argc, char *argv[] ) +int main( int argc, char* argv[] ) { /* For security, make sure we don't dump core */ Crypto::disable_dumping_core(); @@ -178,11 +183,11 @@ int main( int argc, char *argv[] ) /* Detect edge case */ fatal_assert( argc > 0 ); - const char *desired_ip = NULL; + const char* desired_ip = NULL; std::string desired_ip_str; - const char *desired_port = NULL; + const char* desired_port = NULL; std::string command_path; - char **command_argv = NULL; + char** command_argv = NULL; int colors = 0; unsigned int verbose = 0; /* don't close stdin/stdout/stderr */ /* Will cause mosh-server not to correctly detach on old versions of sshd. */ @@ -190,17 +195,17 @@ int main( int argc, char *argv[] ) /* strip off command */ for ( int i = 1; i < argc; i++ ) { - if ( 0 == strcmp( argv[ i ], "--help" ) || 0 == strcmp( argv[ i ], "-h" ) ) { - print_usage( stdout, argv[ 0 ] ); + if ( 0 == strcmp( argv[i], "--help" ) || 0 == strcmp( argv[i], "-h" ) ) { + print_usage( stdout, argv[0] ); exit( 0 ); } - if ( 0 == strcmp( argv[ i ], "--version" ) ) { + if ( 0 == strcmp( argv[i], "--version" ) ) { print_version( stdout ); exit( 0 ); } - if ( 0 == strcmp( argv[ i ], "--" ) ) { /* -- is mandatory */ + if ( 0 == strcmp( argv[i], "--" ) ) { /* -- is mandatory */ if ( i != argc - 1 ) { - command_argv = argv + i + 1; + command_argv = argv + i + 1; } argc = i; /* rest of options before -- */ break; @@ -208,95 +213,94 @@ int main( int argc, char *argv[] ) } /* Parse new command-line syntax */ - if ( (argc >= 2) - && (strcmp( argv[ 1 ], "new" ) == 0) ) { + if ( ( argc >= 2 ) && ( strcmp( argv[1], "new" ) == 0 ) ) { /* new option syntax */ int opt; - while ( (opt = getopt( argc - 1, argv + 1, "@:i:p:c:svl:" )) != -1 ) { + while ( ( opt = getopt( argc - 1, argv + 1, "@:i:p:c:svl:" ) ) != -1 ) { switch ( opt ) { - /* - * This undocumented option does nothing but eat its argument. - * Useful in scripting where you prepend something to a - * mosh-server argv, and might end up with something like - * "mosh-server new -v new -c 256", now you can say - * "mosh-server new -v -@ new -c 256" to discard the second - * "new". - */ - case '@': - break; - case 'i': - desired_ip = optarg; - break; - case 'p': - desired_port = optarg; - break; - case 's': - desired_ip = NULL; - desired_ip_str = get_SSH_IP(); - if ( !desired_ip_str.empty() ) { - desired_ip = desired_ip_str.c_str(); - fatal_assert( desired_ip ); - } - break; - case 'c': - try { - colors = myatoi( optarg ); - } catch ( const CryptoException & ) { - fprintf( stderr, "%s: Bad number of colors (%s)\n", argv[ 0 ], optarg ); - print_usage( stderr, argv[ 0 ] ); - exit( 1 ); - } - break; - case 'v': - verbose++; - break; - case 'l': - locale_vars.push_back( std::string( optarg ) ); - break; - default: - /* don't die on unknown options */ - print_usage( stderr, argv[ 0 ] ); - break; + /* + * This undocumented option does nothing but eat its argument. + * Useful in scripting where you prepend something to a + * mosh-server argv, and might end up with something like + * "mosh-server new -v new -c 256", now you can say + * "mosh-server new -v -@ new -c 256" to discard the second + * "new". + */ + case '@': + break; + case 'i': + desired_ip = optarg; + break; + case 'p': + desired_port = optarg; + break; + case 's': + desired_ip = NULL; + desired_ip_str = get_SSH_IP(); + if ( !desired_ip_str.empty() ) { + desired_ip = desired_ip_str.c_str(); + fatal_assert( desired_ip ); + } + break; + case 'c': + try { + colors = myatoi( optarg ); + } catch ( const CryptoException& ) { + fprintf( stderr, "%s: Bad number of colors (%s)\n", argv[0], optarg ); + print_usage( stderr, argv[0] ); + exit( 1 ); + } + break; + case 'v': + verbose++; + break; + case 'l': + locale_vars.push_back( std::string( optarg ) ); + break; + default: + /* don't die on unknown options */ + print_usage( stderr, argv[0] ); + break; } } } else if ( argc == 1 ) { /* legacy argument parsing for older client wrapper script */ /* do nothing */ } else if ( argc == 2 ) { - desired_ip = argv[ 1 ]; + desired_ip = argv[1]; } else if ( argc == 3 ) { - desired_ip = argv[ 1 ]; - desired_port = argv[ 2 ]; + desired_ip = argv[1]; + desired_port = argv[2]; } else { - print_usage( stderr, argv[ 0 ] ); + print_usage( stderr, argv[0] ); exit( 1 ); } /* Sanity-check arguments */ int dpl, dph; - if ( desired_port && ! Connection::parse_portrange( desired_port, dpl, dph ) ) { - fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[ 0 ], desired_port ); - print_usage( stderr, argv[ 0 ] ); + if ( desired_port && !Connection::parse_portrange( desired_port, dpl, dph ) ) { + fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[0], desired_port ); + print_usage( stderr, argv[0] ); exit( 1 ); } bool with_motd = false; - #ifdef HAVE_SYSLOG - openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_AUTH); - #endif +#ifdef HAVE_SYSLOG + openlog( argv[0], LOG_PID | LOG_NDELAY, LOG_AUTH ); +#endif /* Get shell */ - char *my_argv[ 2 ]; + char* my_argv[2]; std::string shell_name; if ( !command_argv ) { /* get shell name */ - const char *shell = getenv( "SHELL" ); + const char* shell = getenv( "SHELL" ); if ( shell == NULL ) { - struct passwd *pw = getpwuid( getuid() ); + struct passwd* pw = getpwuid( getuid() ); if ( pw == NULL ) { - perror( "getpwuid" ); - exit( 1 ); + perror( "getpwuid" ); + exit( 1 ); } shell = pw->pw_shell; } @@ -308,18 +312,18 @@ int main( int argc, char *argv[] ) command_path = shell_path; - size_t shell_slash( shell_path.rfind('/') ); + size_t shell_slash( shell_path.rfind( '/' ) ); if ( shell_slash == std::string::npos ) { shell_name = shell_path; } else { - shell_name = shell_path.substr(shell_slash + 1); + shell_name = shell_path.substr( shell_slash + 1 ); } /* prepend '-' to make login shell */ shell_name = '-' + shell_name; - my_argv[ 0 ] = const_cast<char *>( shell_name.c_str() ); - my_argv[ 1 ] = NULL; + my_argv[0] = const_cast<char*>( shell_name.c_str() ); + my_argv[1] = NULL; command_argv = my_argv; with_motd = true; @@ -338,13 +342,11 @@ int main( int argc, char *argv[] ) /* apply locale-related environment variables from client */ clear_locale_variables(); - for ( std::list<std::string>::const_iterator i = locale_vars.begin(); - i != locale_vars.end(); - i++ ) { - char *env_string = strdup( i->c_str() ); + for ( std::list<std::string>::const_iterator i = locale_vars.begin(); i != locale_vars.end(); i++ ) { + char* env_string = strdup( i->c_str() ); fatal_assert( env_string ); if ( 0 != putenv( env_string ) ) { - perror( "putenv" ); + perror( "putenv" ); } } @@ -354,39 +356,46 @@ int main( int argc, char *argv[] ) LocaleVar client_ctype = get_ctype(); std::string client_charset( locale_charset() ); - fprintf( stderr, "mosh-server needs a UTF-8 native locale to run.\n\n" - "Unfortunately, the local environment (%s) specifies\n" - "the character set \"%s\",\n\n" - "The client-supplied environment (%s) specifies\n" - "the character set \"%s\".\n\n", - native_ctype.str().c_str(), native_charset.c_str(), client_ctype.str().c_str(), client_charset.c_str() ); - int unused __attribute((unused)) = system( "locale" ); + fprintf( stderr, + "mosh-server needs a UTF-8 native locale to run.\n\n" + "Unfortunately, the local environment (%s) specifies\n" + "the character set \"%s\",\n\n" + "The client-supplied environment (%s) specifies\n" + "the character set \"%s\".\n\n", + native_ctype.str().c_str(), + native_charset.c_str(), + client_ctype.str().c_str(), + client_charset.c_str() ); + int unused __attribute( ( unused ) ) = system( "locale" ); exit( 1 ); } } try { return run_server( desired_ip, desired_port, command_path, command_argv, colors, verbose, with_motd ); - } catch ( const Network::NetworkException &e ) { - fprintf( stderr, "Network exception: %s\n", - e.what() ); + } catch ( const Network::NetworkException& e ) { + fprintf( stderr, "Network exception: %s\n", e.what() ); return 1; - } catch ( const Crypto::CryptoException &e ) { - fprintf( stderr, "Crypto exception: %s\n", - e.what() ); + } catch ( const Crypto::CryptoException& e ) { + fprintf( stderr, "Crypto exception: %s\n", e.what() ); return 1; } } -static int run_server( const char *desired_ip, const char *desired_port, - const std::string &command_path, char *command_argv[], - const int colors, unsigned int verbose, bool with_motd ) { +static int run_server( const char* desired_ip, + const char* desired_port, + const std::string& command_path, + char* command_argv[], + const int colors, + unsigned int verbose, + bool with_motd ) +{ /* get network idle timeout */ long network_timeout = 0; - char *timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" ); + char* timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" ); if ( timeout_envar && *timeout_envar ) { errno = 0; - char *endptr; + char* endptr; network_timeout = strtol( timeout_envar, &endptr, 10 ); if ( *endptr != '\0' || ( network_timeout == 0 && errno == EINVAL ) ) { fputs( "MOSH_SERVER_NETWORK_TMOUT not a valid integer, ignoring\n", stderr ); @@ -397,10 +406,10 @@ static int run_server( const char *desired_ip, const char *desired_port, } /* get network signaled idle timeout */ long network_signaled_timeout = 0; - char *signal_envar = getenv( "MOSH_SERVER_SIGNAL_TMOUT" ); + char* signal_envar = getenv( "MOSH_SERVER_SIGNAL_TMOUT" ); if ( signal_envar && *signal_envar ) { errno = 0; - char *endptr; + char* endptr; network_signaled_timeout = strtol( signal_envar, &endptr, 10 ); if ( *endptr != '\0' || ( network_signaled_timeout == 0 && errno == EINVAL ) ) { fputs( "MOSH_SERVER_SIGNAL_TMOUT not a valid integer, ignoring\n", stderr ); @@ -411,9 +420,7 @@ static int run_server( const char *desired_ip, const char *desired_port, } /* get initial window size */ struct winsize window_size; - if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 || - window_size.ws_col == 0 || - window_size.ws_row == 0 ) { + if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 || window_size.ws_col == 0 || window_size.ws_row == 0 ) { /* Fill in sensible defaults. */ /* They will be overwritten by client on first connection. */ memset( &window_size, 0, sizeof( window_size ) ); @@ -450,7 +457,6 @@ static int run_server( const char *desired_ip, const char *desired_port, fatal_assert( 0 == sigaction( SIGHUP, &sa, NULL ) ); fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) ); - /* detach from terminal */ fflush( NULL ); pid_t the_pid = fork(); @@ -458,16 +464,18 @@ static int run_server( const char *desired_ip, const char *desired_port, perror( "fork" ); } else if ( the_pid > 0 ) { fputs( "\nmosh-server (" PACKAGE_STRING ") [build " BUILD_VERSION "]\n" - "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n" - "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n\n", stderr ); + "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n" + "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n\n", + stderr ); - fprintf( stderr, "[mosh-server detached, pid = %d]\n", static_cast<int>(the_pid) ); + fprintf( stderr, "[mosh-server detached, pid = %d]\n", static_cast<int>( the_pid ) ); #ifndef HAVE_IUTF8 fputs( "\nWarning: termios IUTF8 flag not defined.\n" - "Character-erase of multibyte character sequence\n" - "probably does not work properly on this platform.\n", stderr ); + "Character-erase of multibyte character sequence\n" + "probably does not work properly on this platform.\n", + stderr ); #endif /* HAVE_IUTF8 */ fflush( NULL ); @@ -493,9 +501,8 @@ static int run_server( const char *desired_ip, const char *desired_port, exit( 1 ); } - if ( dup2 ( nullfd, STDIN_FILENO ) < 0 || - dup2 ( nullfd, STDOUT_FILENO ) < 0 || - dup2 ( nullfd, STDERR_FILENO ) < 0 ) { + if ( dup2( nullfd, STDIN_FILENO ) < 0 || dup2( nullfd, STDOUT_FILENO ) < 0 + || dup2( nullfd, STDERR_FILENO ) < 0 ) { perror( "dup2" ); exit( 1 ); } @@ -506,13 +513,13 @@ static int run_server( const char *desired_ip, const char *desired_port, } } - char utmp_entry[ 64 ] = { 0 }; + char utmp_entry[64] = { 0 }; snprintf( utmp_entry, 64, "mosh [%ld]", static_cast<long int>( getpid() ) ); /* Fork child process */ int pipes[2]; - int success = pipe(pipes); - if (success == -1) { + int success = pipe( pipes ); + if ( success == -1 ) { perror( "pipe" ); exit( 1 ); } @@ -538,9 +545,9 @@ static int run_server( const char *desired_ip, const char *desired_port, fatal_assert( 0 == sigaction( SIGHUP, &sa, NULL ) ); fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) ); - #ifdef HAVE_SYSLOG +#ifdef HAVE_SYSLOG closelog(); - #endif +#endif /* close server-related file descriptors */ network.reset(); @@ -565,7 +572,7 @@ static int run_server( const char *desired_ip, const char *desired_port, const char default_term[] = "xterm"; const char color_term[] = "xterm-256color"; - if ( setenv( "TERM", (colors == 256) ? color_term : default_term, true ) < 0 ) { + if ( setenv( "TERM", ( colors == 256 ) ? color_term : default_term, true ) < 0 ) { perror( "setenv" ); exit( 1 ); } @@ -584,7 +591,7 @@ static int run_server( const char *desired_ip, const char *desired_port, chdir_homedir(); - if ( with_motd && (!motd_hushed()) ) { + if ( with_motd && ( !motd_hushed() ) ) { // On illumos motd is printed by /etc/profile. #ifndef __sun // For Ubuntu, try and print one of {,/var}/run/motd.dynamic. @@ -593,11 +600,11 @@ static int run_server( const char *desired_ip, const char *desired_port, // this always happens. // XXX Hackish knowledge of Ubuntu PAM configuration. // But this seems less awful than build-time detection with autoconf. - if (!print_motd("/run/motd.dynamic")) { - print_motd("/var/run/motd.dynamic"); + if ( !print_motd( "/run/motd.dynamic" ) ) { + print_motd( "/var/run/motd.dynamic" ); } // Always print traditional /etc/motd. - print_motd("/etc/motd"); + print_motd( "/etc/motd" ); #endif warn_unattached( utmp_entry ); } @@ -607,9 +614,9 @@ static int run_server( const char *desired_ip, const char *desired_port, // -1, errno == EINTR -- retry // otherwise, give up while ( read( pipes[0], linebuf, sizeof( linebuf ) ) == -1 ) { - if ( errno != EINTR ) { - err( 1, "parent signal" ); - } + if ( errno != EINTR ) { + err( 1, "parent signal" ); + } } Crypto::reenable_dumping_core(); @@ -621,20 +628,20 @@ static int run_server( const char *desired_ip, const char *desired_port, } if ( close( pipes[0] ) < 0 ) { - perror( "child read pipe close" ); - exit( 1 ); + perror( "child read pipe close" ); + exit( 1 ); } } else { - /* parent */ - if ( close(pipes[0]) < 0 ) { - perror( "parent read pipe close" ); - exit( 1 ); - } + /* parent */ + if ( close( pipes[0] ) < 0 ) { + perror( "parent read pipe close" ); + exit( 1 ); + } /* Drop unnecessary privileges */ #ifdef HAVE_PLEDGE /* OpenBSD pledge() syscall */ - if ( pledge( "stdio inet tty", NULL )) { + if ( pledge( "stdio inet tty", NULL ) ) { perror( "pledge() failed" ); exit( 1 ); } @@ -647,17 +654,15 @@ static int run_server( const char *desired_ip, const char *desired_port, try { serve( master, pipes[1], terminal, *network, network_timeout, network_signaled_timeout ); - } catch ( const Network::NetworkException &e ) { - fprintf( stderr, "Network exception: %s\n", - e.what() ); - } catch ( const Crypto::CryptoException &e ) { - fprintf( stderr, "Crypto exception: %s\n", - e.what() ); + } catch ( const Network::NetworkException& e ) { + fprintf( stderr, "Network exception: %s\n", e.what() ); + } catch ( const Crypto::CryptoException& e ) { + fprintf( stderr, "Crypto exception: %s\n", e.what() ); } - #ifdef HAVE_UTEMPTER +#ifdef HAVE_UTEMPTER utempter_remove_record( master ); - #endif +#endif if ( close( master ) < 0 ) { perror( "close" ); @@ -670,35 +675,40 @@ static int run_server( const char *desired_ip, const char *desired_port, return 0; } -static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, ServerConnection &network, long network_timeout, long network_signaled_timeout ) +static void serve( int host_fd, + int pipe_fd, + Terminal::Complete& terminal, + ServerConnection& network, + long network_timeout, + long network_signaled_timeout ) { /* scale timeouts */ const uint64_t network_timeout_ms = static_cast<uint64_t>( network_timeout ) * 1000; const uint64_t network_signaled_timeout_ms = static_cast<uint64_t>( network_signaled_timeout ) * 1000; /* prepare to poll for events */ - Select &sel = Select::get_instance(); + Select& sel = Select::get_instance(); sel.add_signal( SIGTERM ); sel.add_signal( SIGINT ); sel.add_signal( SIGUSR1 ); uint64_t last_remote_num = network.get_remote_state_num(); - #ifdef HAVE_UTEMPTER +#ifdef HAVE_UTEMPTER bool connected_utmp = false; - #endif - #if defined(HAVE_SYSLOG) || defined(HAVE_UTEMPTER) +#endif +#if defined( HAVE_SYSLOG ) || defined( HAVE_UTEMPTER ) bool force_connection_change_evt = false; Addr saved_addr; socklen_t saved_addr_len = 0; - #endif +#endif - #ifdef HAVE_SYSLOG - struct passwd *pw = getpwuid( getuid() ); - if (pw == NULL) { +#ifdef HAVE_SYSLOG + struct passwd* pw = getpwuid( getuid() ); + if ( pw == NULL ) { throw NetworkException( std::string( "serve: getpwuid: " ) + strerror( errno ), 0 ); } - syslog(LOG_INFO, "user %s session begin", pw->pw_name); - #endif + syslog( LOG_INFO, "user %s session begin", pw->pw_name ); +#endif bool child_released = false; @@ -710,8 +720,7 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve timeout = std::min( timeout, network.wait_time() ); timeout = std::min( timeout, terminal.wait_time( now ) ); - if ( (!network.get_remote_state_num()) - || network.shutdown_in_progress() ) { + if ( ( !network.get_remote_state_num() ) || network.shutdown_in_progress() ) { timeout = std::min( timeout, 5000 ); } /* @@ -719,31 +728,30 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve * We may want to wake up sooner. */ if ( network_timeout_ms ) { - int64_t network_sleep = network_timeout_ms - - ( now - network.get_latest_remote_state().timestamp ); - if ( network_sleep < 0 ) { - network_sleep = 0; - } else if ( network_sleep > INT_MAX ) { - /* 24 days might be too soon. That's OK. */ - network_sleep = INT_MAX; - } - timeout = std::min( timeout, static_cast<int>(network_sleep) ); + int64_t network_sleep = network_timeout_ms - ( now - network.get_latest_remote_state().timestamp ); + if ( network_sleep < 0 ) { + network_sleep = 0; + } else if ( network_sleep > INT_MAX ) { + /* 24 days might be too soon. That's OK. */ + network_sleep = INT_MAX; + } + timeout = std::min( timeout, static_cast<int>( network_sleep ) ); } /* poll for events */ sel.clear_fds(); - std::vector< int > fd_list( network.fds() ); + std::vector<int> fd_list( network.fds() ); assert( fd_list.size() == 1 ); /* servers don't hop */ int network_fd = fd_list.back(); sel.add_fd( network_fd ); if ( !network.shutdown_in_progress() ) { - sel.add_fd( host_fd ); + sel.add_fd( host_fd ); } int active_fds = sel.select( timeout ); if ( active_fds < 0 ) { - perror( "select" ); - break; + perror( "select" ); + break; } now = Network::timestamp(); @@ -751,203 +759,199 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve std::string terminal_to_host; if ( sel.read( network_fd ) ) { - /* packet received from the network */ - network.recv(); - - /* is new user input available for the terminal? */ - if ( network.get_remote_state_num() != last_remote_num ) { - last_remote_num = network.get_remote_state_num(); - - - Network::UserStream us; - us.apply_string( network.get_remote_diff() ); - /* apply userstream to terminal */ - for ( size_t i = 0; i < us.size(); i++ ) { - const Parser::Action &action = us.get_action( i ); - if ( typeid( action ) == typeid( Parser::Resize ) ) { - /* apply only the last consecutive Resize action */ - if ( i < us.size() - 1 ) { - const Parser::Action &next = us.get_action( i + 1 ); - if ( typeid( next ) == typeid( Parser::Resize ) ) { - continue; - } - } - /* tell child process of resize */ - const Parser::Resize &res = static_cast<const Parser::Resize &>( action ); - struct winsize window_size; - if ( ioctl( host_fd, TIOCGWINSZ, &window_size ) < 0 ) { - perror( "ioctl TIOCGWINSZ" ); - network.start_shutdown(); - } - window_size.ws_col = res.width; - window_size.ws_row = res.height; - if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) { - perror( "ioctl TIOCSWINSZ" ); - network.start_shutdown(); - } - } - terminal_to_host += terminal.act( action ); - } - - if ( !us.empty() ) { - /* register input frame number for future echo ack */ - terminal.register_input_frame( last_remote_num, now ); - } - - /* update client with new state of terminal */ - if ( !network.shutdown_in_progress() ) { - network.set_current_state( terminal ); - } - #if defined(HAVE_SYSLOG) || defined(HAVE_UTEMPTER) - #ifdef HAVE_UTEMPTER - if (!connected_utmp) { - force_connection_change_evt = true; - } else { - force_connection_change_evt = false; - } - #else - force_connection_change_evt = false; - #endif - - /** - * - HAVE_UTEMPTER - update utmp entry if we have become "connected" - * - HAVE_SYSLOG - log connection information to syslog - **/ - if ( (force_connection_change_evt) - || saved_addr_len != network.get_remote_addr_len() - || memcmp( &saved_addr, &network.get_remote_addr(), - saved_addr_len ) != 0 ) { - - saved_addr = network.get_remote_addr(); - saved_addr_len = network.get_remote_addr_len(); - - char host[ NI_MAXHOST ]; - int errcode = getnameinfo( &saved_addr.sa, saved_addr_len, - host, sizeof( host ), NULL, 0, - NI_NUMERICHOST ); - if ( errcode != 0 ) { - throw NetworkException( std::string( "serve: getnameinfo: " ) + gai_strerror( errcode ), 0 ); - } - - #ifdef HAVE_UTEMPTER - utempter_remove_record( host_fd ); - char tmp[ 64 + NI_MAXHOST ]; - snprintf( tmp, 64 + NI_MAXHOST, "%s via mosh [%ld]", host, static_cast<long int>( getpid() ) ); - utempter_add_record( host_fd, tmp ); - - connected_utmp = true; - #endif - - #ifdef HAVE_SYSLOG - syslog(LOG_INFO, "user %s connected from host: %s", pw->pw_name, host); - #endif - } - #endif - - /* Tell child to start login session. */ - if ( !child_released ) { - if ( close( pipe_fd ) < 0 ) { - err( 1, "child release" ); - } - child_released = true; - } - } + /* packet received from the network */ + network.recv(); + + /* is new user input available for the terminal? */ + if ( network.get_remote_state_num() != last_remote_num ) { + last_remote_num = network.get_remote_state_num(); + + Network::UserStream us; + us.apply_string( network.get_remote_diff() ); + /* apply userstream to terminal */ + for ( size_t i = 0; i < us.size(); i++ ) { + const Parser::Action& action = us.get_action( i ); + if ( typeid( action ) == typeid( Parser::Resize ) ) { + /* apply only the last consecutive Resize action */ + if ( i < us.size() - 1 ) { + const Parser::Action& next = us.get_action( i + 1 ); + if ( typeid( next ) == typeid( Parser::Resize ) ) { + continue; + } + } + /* tell child process of resize */ + const Parser::Resize& res = static_cast<const Parser::Resize&>( action ); + struct winsize window_size; + if ( ioctl( host_fd, TIOCGWINSZ, &window_size ) < 0 ) { + perror( "ioctl TIOCGWINSZ" ); + network.start_shutdown(); + } + window_size.ws_col = res.width; + window_size.ws_row = res.height; + if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) { + perror( "ioctl TIOCSWINSZ" ); + network.start_shutdown(); + } + } + terminal_to_host += terminal.act( action ); + } + + if ( !us.empty() ) { + /* register input frame number for future echo ack */ + terminal.register_input_frame( last_remote_num, now ); + } + + /* update client with new state of terminal */ + if ( !network.shutdown_in_progress() ) { + network.set_current_state( terminal ); + } +#if defined( HAVE_SYSLOG ) || defined( HAVE_UTEMPTER ) +#ifdef HAVE_UTEMPTER + if ( !connected_utmp ) { + force_connection_change_evt = true; + } else { + force_connection_change_evt = false; + } +#else + force_connection_change_evt = false; +#endif + + /** + * - HAVE_UTEMPTER - update utmp entry if we have become "connected" + * - HAVE_SYSLOG - log connection information to syslog + **/ + if ( ( force_connection_change_evt ) || saved_addr_len != network.get_remote_addr_len() + || memcmp( &saved_addr, &network.get_remote_addr(), saved_addr_len ) != 0 ) { + + saved_addr = network.get_remote_addr(); + saved_addr_len = network.get_remote_addr_len(); + + char host[NI_MAXHOST]; + int errcode + = getnameinfo( &saved_addr.sa, saved_addr_len, host, sizeof( host ), NULL, 0, NI_NUMERICHOST ); + if ( errcode != 0 ) { + throw NetworkException( std::string( "serve: getnameinfo: " ) + gai_strerror( errcode ), 0 ); + } + +#ifdef HAVE_UTEMPTER + utempter_remove_record( host_fd ); + char tmp[64 + NI_MAXHOST]; + snprintf( tmp, 64 + NI_MAXHOST, "%s via mosh [%ld]", host, static_cast<long int>( getpid() ) ); + utempter_add_record( host_fd, tmp ); + + connected_utmp = true; +#endif + +#ifdef HAVE_SYSLOG + syslog( LOG_INFO, "user %s connected from host: %s", pw->pw_name, host ); +#endif + } +#endif + + /* Tell child to start login session. */ + if ( !child_released ) { + if ( close( pipe_fd ) < 0 ) { + err( 1, "child release" ); + } + child_released = true; + } + } } - - if ( (!network.shutdown_in_progress()) && sel.read( host_fd ) ) { - /* input from the host needs to be fed to the terminal */ - const int buf_size = 16384; - char buf[ buf_size ]; - - /* fill buffer if possible */ - ssize_t bytes_read = read( host_fd, buf, buf_size ); + + if ( ( !network.shutdown_in_progress() ) && sel.read( host_fd ) ) { + /* input from the host needs to be fed to the terminal */ + const int buf_size = 16384; + char buf[buf_size]; + + /* fill buffer if possible */ + ssize_t bytes_read = read( host_fd, buf, buf_size ); /* If the pty slave is closed, reading from the master can fail with EIO (see #264). So we treat errors on read() like EOF. */ if ( bytes_read <= 0 ) { - network.start_shutdown(); - } else { - terminal_to_host += terminal.act( std::string( buf, bytes_read ) ); - - /* update client with new state of terminal */ - network.set_current_state( terminal ); - } + network.start_shutdown(); + } else { + terminal_to_host += terminal.act( std::string( buf, bytes_read ) ); + + /* update client with new state of terminal */ + network.set_current_state( terminal ); + } } /* write user input and terminal writeback to the host */ if ( swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) { - network.start_shutdown(); + network.start_shutdown(); } bool idle_shutdown = false; - if ( network_timeout_ms && - network_timeout_ms <= time_since_remote_state ) { - idle_shutdown = true; - fprintf( stderr, "Network idle for %llu seconds.\n", - static_cast<unsigned long long>( time_since_remote_state / 1000 ) ); + if ( network_timeout_ms && network_timeout_ms <= time_since_remote_state ) { + idle_shutdown = true; + fprintf( stderr, + "Network idle for %llu seconds.\n", + static_cast<unsigned long long>( time_since_remote_state / 1000 ) ); } if ( sel.signal( SIGUSR1 ) - && ( !network_signaled_timeout_ms || network_signaled_timeout_ms <= time_since_remote_state ) ) { - idle_shutdown = true; - fprintf( stderr, "Network idle for %llu seconds when SIGUSR1 received\n", - static_cast<unsigned long long>( time_since_remote_state / 1000 ) ); + && ( !network_signaled_timeout_ms || network_signaled_timeout_ms <= time_since_remote_state ) ) { + idle_shutdown = true; + fprintf( stderr, + "Network idle for %llu seconds when SIGUSR1 received\n", + static_cast<unsigned long long>( time_since_remote_state / 1000 ) ); } if ( sel.any_signal() || idle_shutdown ) { - /* shutdown signal */ - if ( network.has_remote_addr() && (!network.shutdown_in_progress()) ) { - network.start_shutdown(); - } else { - break; - } + /* shutdown signal */ + if ( network.has_remote_addr() && ( !network.shutdown_in_progress() ) ) { + network.start_shutdown(); + } else { + break; + } } - + /* quit if our shutdown has been acknowledged */ if ( network.shutdown_in_progress() && network.shutdown_acknowledged() ) { - break; + break; } /* quit after shutdown acknowledgement timeout */ if ( network.shutdown_in_progress() && network.shutdown_ack_timed_out() ) { - break; + break; } /* quit if we received and acknowledged a shutdown request */ if ( network.counterparty_shutdown_ack_sent() ) { - break; + break |