NSM Proxy: Detect, log, and display startup errors of proxied process.

This commit is contained in:
Jonathan Moore Liles 2014-09-22 20:44:42 -07:00
parent 6bd899f223
commit e230929a57
2 changed files with 119 additions and 11 deletions

View File

@ -26,6 +26,7 @@
#define APP_TITLE "NSM Proxy" #define APP_TITLE "NSM Proxy"
#include <FL/Fl_File_Chooser.H> #include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Text_Display.H>
#include "NSM_Proxy_UI.H" #include "NSM_Proxy_UI.H"
#include <lo/lo.h> #include <lo/lo.h>
#include <signal.h> #include <signal.h>
@ -38,6 +39,8 @@ lo_address nsmp_addr;
static NSM_Proxy_UI *ui; static NSM_Proxy_UI *ui;
static char *client_error;
int int
osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{ {
@ -73,6 +76,16 @@ osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_me
else if ( argv[0]->i == SIGHUP ) else if ( argv[0]->i == SIGHUP )
ui->stop_signal_choice->value( 2 ); ui->stop_signal_choice->value( 2 );
} }
if (!strcmp( path, "/nsm/proxy/client_error" ))
{
if ( client_error != NULL )
free(client_error);
client_error = NULL;
if ( strlen(&argv[0]->s) > 0 )
client_error = strdup(&argv[0]->s);
}
Fl::unlock(); Fl::unlock();
@ -101,6 +114,7 @@ init_osc ( const char *osc_port )
lo_server_thread_add_method( loth, "/nsm/proxy/label", "s", osc_update, NULL ); lo_server_thread_add_method( loth, "/nsm/proxy/label", "s", osc_update, NULL );
lo_server_thread_add_method( loth, "/nsm/proxy/save_signal", "i", osc_update, NULL ); lo_server_thread_add_method( loth, "/nsm/proxy/save_signal", "i", osc_update, NULL );
lo_server_thread_add_method( loth, "/nsm/proxy/stop_signal", "i", osc_update, NULL ); lo_server_thread_add_method( loth, "/nsm/proxy/stop_signal", "i", osc_update, NULL );
lo_server_thread_add_method( loth, "/nsm/proxy/client_error", "s", osc_update, NULL );
lo_server_thread_start( loth ); lo_server_thread_start( loth );
} }
@ -202,6 +216,46 @@ connect_ui ( void )
void cb_dismiss_button ( Fl_Widget *w, void *v )
{
w->window()->hide();
}
void
check_error ( void *v )
{
if ( client_error )
{
{
Fl_Double_Window *o = new Fl_Double_Window(600,300+15,"Abnormal Termination");
{
Fl_Box *o = new Fl_Box(0+15,0+15,600-30,50);
o->box(FL_BORDER_BOX);
o->color(FL_RED);
o->labelcolor(FL_WHITE);
o->align(FL_ALIGN_CENTER|FL_ALIGN_WRAP);
o->copy_label( client_error );
}
{
Fl_Text_Display *o = new Fl_Text_Display(0+15,50+15,600-30,300-75-30);
o->buffer(new Fl_Text_Buffer());
o->buffer()->loadfile( "error.log" );
}
{
Fl_Button *o = new Fl_Button(600-75-15,300-25,75,25,"Dismiss");
o->callback(cb_dismiss_button,0);
}
o->show();
}
free(client_error);
client_error = NULL;
}
Fl::repeat_timeout( 0.5f, check_error, v );
}
int int
main ( int argc, char **argv ) main ( int argc, char **argv )
{ {
@ -229,6 +283,8 @@ main ( int argc, char **argv )
Fl::lock(); Fl::lock();
Fl::add_timeout( 0.5f, check_error, NULL );
Fl::run(); Fl::run();
return 0; return 0;

View File

@ -51,6 +51,7 @@ static char *nsm_display_name;
#define CONFIG_FILE_NAME "nsm-proxy.config" #define CONFIG_FILE_NAME "nsm-proxy.config"
void show_gui ( void );
class NSM_Proxy { class NSM_Proxy {
@ -61,26 +62,47 @@ class NSM_Proxy {
int _save_signal; int _save_signal;
int _stop_signal; int _stop_signal;
int _pid; int _pid;
char *_client_error;
public: public:
int stop_signal ( void ) {return _stop_signal;}
NSM_Proxy ( ) NSM_Proxy ( )
{ {
_label = _executable = _arguments = _config_file = 0; _label = _executable = _arguments = _config_file = 0;
_save_signal = 0; _save_signal = 0;
_stop_signal = SIGTERM; _stop_signal = SIGTERM;
_pid = 0; _pid = 0;
_client_error = 0;
} }
~NSM_Proxy ( ) ~NSM_Proxy ( )
{ {
} }
void handle_client_death ( int status )
{
printf( "proxied process died unexpectedly... not dying\n" );
/* proxied process died unexpectedly */
if ( _client_error != NULL )
free(_client_error);
asprintf(&_client_error, "The proxied process terminated abnormally during invocation. Exit status: %i.", status );
show_gui();
_pid = 0;
}
void kill ( void ) void kill ( void )
{ {
if ( _pid ) if ( _pid )
{
::kill( _pid, _stop_signal ); ::kill( _pid, _stop_signal );
} }
}
bool start ( const char *executable, const char *arguments, const char *config_file ) bool start ( const char *executable, const char *arguments, const char *config_file )
{ {
@ -130,11 +152,11 @@ public:
char *cmd; char *cmd;
if ( _arguments ) if ( _arguments )
asprintf( &cmd, "exec %s %s", _executable, _arguments ); asprintf( &cmd, "exec %s %s >error.log 2>&1", _executable, _arguments );
else else
asprintf( &cmd, "exec %s", _executable ); asprintf( &cmd, "exec %s >error.log 2>&1", _executable );
char *args[] = { _executable, strdup( "-c" ), cmd, NULL }; char *args[] = { strdup("/bin/sh"), strdup( "-c" ), cmd, NULL };
setenv( "NSM_CLIENT_ID", nsm_client_id, 1 ); setenv( "NSM_CLIENT_ID", nsm_client_id, 1 );
setenv( "NSM_SESSION_NAME", nsm_display_name, 1 ); setenv( "NSM_SESSION_NAME", nsm_display_name, 1 );
@ -145,8 +167,7 @@ public:
if ( -1 == execvp( "/bin/sh", args ) ) if ( -1 == execvp( "/bin/sh", args ) )
{ {
WARNING( "Error starting process: %s", strerror( errno ) ); WARNING( "Error starting process: %s", strerror( errno ) );
exit(1);
exit(-1);
} }
} }
@ -222,7 +243,6 @@ public:
bool restore ( const char *path ) bool restore ( const char *path )
{ {
FILE *fp = fopen( path, "r" ); FILE *fp = fopen( path, "r" );
if ( ! fp ) if ( ! fp )
{ {
WARNING( "Error opening file for restore: %s", strerror( errno ) ); WARNING( "Error opening file for restore: %s", strerror( errno ) );
@ -285,6 +305,9 @@ public:
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/arguments", "s", _arguments ? _arguments : "" ); lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/arguments", "s", _arguments ? _arguments : "" );
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/config_file", "s", _config_file ? _config_file : "" ); lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/config_file", "s", _config_file ? _config_file : "" );
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/stop_signal", "i", _stop_signal ); lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/stop_signal", "i", _stop_signal );
lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/client_error", "s", _client_error ? _client_error : "" );
} }
}; };
@ -400,7 +423,7 @@ show_gui ( void )
{ {
WARNING( "Error starting process: %s", strerror( errno ) ); WARNING( "Error starting process: %s", strerror( errno ) );
exit(-1); exit(1);
} }
} }
@ -649,10 +672,39 @@ void handle_sigchld ( )
continue; continue;
} }
/* otherwise, it was our proxied process that died, so we should die too */ if ( WIFSIGNALED(status) )
printf( "proxied process died... nsm-proxy dying too\n" ); {
/* process was killed via signal */
if (WTERMSIG(status) == SIGTERM ||
WTERMSIG(status) == SIGHUP ||
WTERMSIG(status) == SIGINT ||
WTERMSIG(status) == SIGKILL )
{
/* process was killed via an appropriate signal */
MESSAGE( "child was killed (maybe by us)\n" );
die_now = 1; die_now = 1;
continue;
}
}
else if ( WIFEXITED(status) )
{
/* child called exit() or returned from main() */
MESSAGE( "child exit status: %i", WEXITSTATUS(status) );
if ( WEXITSTATUS(status) == 0 )
{
/* apparently normal termination */
MESSAGE( "child exited without error.");
die_now = 1;
continue;
}
else
{
MESSAGE("child exited abnormally.");
nsm_proxy->handle_client_death(WEXITSTATUS(status));
}
}
} }
} }