Detach from terminal before forkpty(). fixes #8 (github issue)

This commit is contained in:
Keith Winstein
2012-02-13 01:39:33 -05:00
parent e67f6c5da7
commit 20f03791a3
+59 -50
View File
@@ -38,7 +38,11 @@
#include "networktransport.cc" #include "networktransport.cc"
void serve( int host_fd, const char *desired_ip ); typedef Network::Transport< Terminal::Complete, Network::UserStream > ServerConnection;
void serve( int host_fd,
Terminal::Complete &terminal,
ServerConnection &network );
using namespace std; using namespace std;
@@ -54,9 +58,6 @@ int main( int argc, char *argv[] )
exit( 1 ); exit( 1 );
} }
int master;
struct termios child_termios;
/* Adopt implementation locale */ /* Adopt implementation locale */
if ( NULL == setlocale( LC_ALL, "" ) ) { if ( NULL == setlocale( LC_ALL, "" ) ) {
perror( "setlocale" ); perror( "setlocale" );
@@ -69,12 +70,55 @@ int main( int argc, char *argv[] )
exit( 1 ); exit( 1 );
} }
/* Verify terminal configuration */ /* get initial window size */
struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
exit( 1 );
}
/* open parser and terminal */
Terminal::Complete terminal( window_size.ws_col, window_size.ws_row );
/* open network */
Network::UserStream blank;
ServerConnection network( terminal, blank, desired_ip );
/* network.set_verbose(); */
printf( "MOSH CONNECT %d %s\n", network.port(), network.get_key().c_str() );
fflush( stdout );
/* don't let signals kill us */
sigset_t signals_to_block;
assert( sigemptyset( &signals_to_block ) == 0 );
assert( sigaddset( &signals_to_block, SIGTERM ) == 0 );
assert( sigaddset( &signals_to_block, SIGINT ) == 0 );
assert( sigaddset( &signals_to_block, SIGHUP ) == 0 );
assert( sigaddset( &signals_to_block, SIGPIPE ) == 0 );
assert( sigprocmask( SIG_BLOCK, &signals_to_block, NULL ) == 0 );
struct termios child_termios;
/* Get terminal configuration */
if ( tcgetattr( STDIN_FILENO, &child_termios ) < 0 ) { if ( tcgetattr( STDIN_FILENO, &child_termios ) < 0 ) {
perror( "tcgetattr" ); perror( "tcgetattr" );
exit( 1 ); exit( 1 );
} }
/* detach from terminal */
pid_t the_pid = fork();
if ( the_pid < 0 ) {
perror( "fork" );
} else if ( the_pid > 0 ) {
_exit( 0 );
}
fprintf( stderr, "[mosh-server detached, pid=%d.]\n", (int)getpid() );
int master;
if ( !(child_termios.c_iflag & IUTF8) ) { if ( !(child_termios.c_iflag & IUTF8) ) {
/* SSH should also convey IUTF8 across connection. */ /* SSH should also convey IUTF8 across connection. */
// fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" ); // fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" );
@@ -91,6 +135,13 @@ int main( int argc, char *argv[] )
if ( child == 0 ) { if ( child == 0 ) {
/* child */ /* child */
/* unblock signals */
sigset_t signals_to_block;
assert( sigemptyset( &signals_to_block ) == 0 );
assert( sigprocmask( SIG_SETMASK, &signals_to_block, NULL ) == 0 );
/* set TERM */
if ( setenv( "TERM", "xterm", true ) < 0 ) { if ( setenv( "TERM", "xterm", true ) < 0 ) {
perror( "setenv" ); perror( "setenv" );
exit( 1 ); exit( 1 );
@@ -128,7 +179,7 @@ int main( int argc, char *argv[] )
} else { } else {
/* parent */ /* parent */
try { try {
serve( master, desired_ip ); serve( master, terminal, network );
} catch ( Network::NetworkException e ) { } catch ( Network::NetworkException e ) {
fprintf( stderr, "Network exception: %s: %s\n", fprintf( stderr, "Network exception: %s: %s\n",
e.function.c_str(), strerror( e.the_errno ) ); e.function.c_str(), strerror( e.the_errno ) );
@@ -148,7 +199,7 @@ int main( int argc, char *argv[] )
return 0; return 0;
} }
void serve( int host_fd, const char *desired_ip ) void serve( int host_fd, Terminal::Complete &terminal, ServerConnection &network )
{ {
/* establish fd for shutdown signals */ /* establish fd for shutdown signals */
sigset_t signal_mask; sigset_t signal_mask;
@@ -157,55 +208,12 @@ void serve( int host_fd, const char *desired_ip )
assert( sigaddset( &signal_mask, SIGTERM ) == 0 ); assert( sigaddset( &signal_mask, SIGTERM ) == 0 );
assert( sigaddset( &signal_mask, SIGINT ) == 0 ); assert( sigaddset( &signal_mask, SIGINT ) == 0 );
sigset_t signals_to_block = signal_mask;
assert( sigaddset( &signals_to_block, SIGHUP ) == 0 );
assert( sigaddset( &signals_to_block, SIGPIPE ) == 0 );
/* don't let signals kill us */
assert( sigprocmask( SIG_BLOCK, &signals_to_block, NULL ) == 0 );
int shutdown_signal_fd = signalfd( -1, &signal_mask, 0 ); int shutdown_signal_fd = signalfd( -1, &signal_mask, 0 );
if ( shutdown_signal_fd < 0 ) { if ( shutdown_signal_fd < 0 ) {
perror( "signalfd" ); perror( "signalfd" );
return; return;
} }
/* get initial window size */
struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
return;
}
/* tell child process */
if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCSWINSZ" );
return;
}
/* open parser and terminal */
Terminal::Complete terminal( window_size.ws_col, window_size.ws_row );
/* open network */
Network::UserStream blank;
Network::Transport< Terminal::Complete, Network::UserStream > network( terminal, blank, desired_ip );
/* network.set_verbose(); */
printf( "MOSH CONNECT %d %s\n", network.port(), network.get_key().c_str() );
fflush( stdout );
/* detach from terminal */
pid_t the_pid = fork();
if ( the_pid < 0 ) {
perror( "fork" );
} else if ( the_pid > 0 ) {
_exit( 0 );
}
fprintf( stderr, "[mosh-server detached, pid=%d.]\n", (int)getpid() );
/* prepare to poll for events */ /* prepare to poll for events */
struct pollfd pollfds[ 3 ]; struct pollfd pollfds[ 3 ];
@@ -244,6 +252,7 @@ void serve( int host_fd, const char *desired_ip )
if ( typeid( *us.get_action( i ) ) == typeid( Parser::Resize ) ) { if ( typeid( *us.get_action( i ) ) == typeid( Parser::Resize ) ) {
/* tell child process of resize */ /* tell child process of resize */
const Parser::Resize *res = static_cast<const Parser::Resize *>( us.get_action( i ) ); const Parser::Resize *res = static_cast<const Parser::Resize *>( us.get_action( i ) );
struct winsize window_size;
window_size.ws_col = res->width; window_size.ws_col = res->width;
window_size.ws_row = res->height; window_size.ws_row = res->height;
if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) { if ( ioctl( host_fd, TIOCSWINSZ, &window_size ) < 0 ) {