2 /*******************************************************************************/
3 /* Copyright (C) 2012 Jonathan Moore Liles */
5 /* This program is free software; you can redistribute it and/or modify it */
6 /* under the terms of the GNU General Public License as published by the */
7 /* Free Software Foundation; either version 2 of the License, or (at your */
8 /* option) any later version. */
10 /* This program is distributed in the hope that it will be useful, but WITHOUT */
11 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
12 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
15 /* You should have received a copy of the GNU General Public License along */
16 /* with This program; see the file COPYING. If not,write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /*******************************************************************************/
20 #pragma GCC diagnostic ignored "-Wunused-parameter"
22 #define _MODULE_ "nsm-proxy"
23 #define APP_NAME "NSM Proxy"
24 #define APP_TITLE "NSM Proxy"
35 #include <sys/types.h>
37 #include <sys/signalfd.h>
41 static lo_server losrv;
42 static lo_address nsm_addr;
43 static lo_address gui_addr;
44 static int nsm_is_active;
45 static char *project_file;
46 static int die_now = 0;
49 static char *nsm_client_id;
50 static char *nsm_display_name;
52 #define CONFIG_FILE_NAME "nsm-proxy.config"
66 _label = _executable = _arguments = 0;
78 ::kill( _pid, SIGTERM );
81 bool start ( const char *executable, const char *arguments )
88 _executable = strdup( executable );
91 _arguments = strdup( arguments );
101 /* already running */
105 if ( ! (pid = fork()) )
107 MESSAGE( "Launching %s\n", _executable );
109 // char *args[] = { strdup( executable ), NULL };
114 asprintf( &cmd, "exec %s %s", _executable, _arguments );
116 asprintf( &cmd, "exec %s", _executable );
118 char *args[] = { _executable, strdup( "-c" ), cmd, NULL };
120 setenv( "NSM_CLIENT_ID", nsm_client_id, 1 );
121 setenv( "NSM_SESSION_NAME", nsm_display_name, 1 );
123 if ( -1 == execvp( "/bin/sh", args ) )
125 WARNING( "Error starting process: %s", strerror( errno ) );
136 void save_signal ( int s )
141 void label ( const char *s )
146 _label = strdup( s );
148 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/label", "s", _label );
153 DMESSAGE( "Sending process save signal" );
155 ::kill( _pid, _save_signal );
159 bool dump ( const char *path )
161 FILE *fp = fopen( path, "w" );
165 WARNING( "Error opening file for saving: %s", strerror( errno ) );
169 if ( _executable && strlen(_executable) )
170 fprintf( fp, "executable\n\t%s\n", _executable );
172 if ( _arguments && strlen(_arguments) )
173 fprintf( fp, "arguments\n\t%s\n", _arguments );
175 fprintf( fp, "save signal\n\t%i\n", _save_signal );
177 if ( _label && strlen(_label) )
178 fprintf( fp, "label\n\t%s\n", _label );
185 bool restore ( const char *path )
187 FILE *fp = fopen( path, "r" );
191 WARNING( "Error opening file for restore: %s", strerror( errno ) );
198 MESSAGE( "Loading file config \"%s\"", path );
200 while ( 2 == fscanf( fp, "%a[^\n]\n\t%a[^\n]\n", &name, &value ) )
203 DMESSAGE( "%s=%s", name, value );
205 if ( !strcmp( name, "executable" ) )
207 else if (!strcmp( name, "arguments" ) )
209 else if ( !strcmp( name, "save signal" ) )
211 _save_signal = atoi( value );
214 else if ( !strcmp( name, "label" ) )
221 WARNING( "Unknown option \"%s\" in config file", name );
234 void update ( lo_address to )
236 DMESSAGE( "Sending update" );
238 lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/save_signal", "i", _save_signal );
239 lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/label", "s", _label ? _label : "" );
240 lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/executable", "s", _executable ? _executable : "" );
241 lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/arguments", "s", _arguments ? _arguments : "" );
245 NSM_Proxy *nsm_proxy;
248 announce ( const char *nsm_url, const char *client_name, const char *process_name )
250 printf( "Announcing to NSM\n" );
252 lo_address to = lo_address_new_from_url( nsm_url );
254 int pid = (int)getpid();
256 lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
260 1, /* api_major_version */
261 0, /* api_minor_version */
264 lo_address_free( to );
268 snapshot ( const char *file )
270 /* mkdir( file, 0777 ); */
273 asprintf( &path, "%s/%s", file, CONFIG_FILE_NAME );
275 bool r = nsm_proxy->dump( path );
283 open ( const char *file )
286 asprintf( &path, "%s/%s", file, CONFIG_FILE_NAME );
288 bool r = nsm_proxy->restore( path );
302 osc_announce_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
304 if ( strcmp( types, "sis" ) )
307 if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
310 printf( "Failed to register with NSM: %s\n", &argv[2]->s );
318 osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
320 if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
323 printf( "Successfully registered. NSM says: %s", &argv[1]->s );
326 nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ) );
332 osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
334 bool r = snapshot( project_file );
339 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
341 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Error saving project file" );
353 if ( ! (pid = fork()) )
355 char executable[] = "nsm-proxy-gui";
357 MESSAGE( "Launching %s\n", executable );
359 char *url = lo_server_get_url( losrv );
361 char *args[] = { executable, strdup( "--connect-to" ), url, NULL };
363 if ( -1 == execvp( executable, args ) )
365 WARNING( "Error starting process: %s", strerror( errno ) );
373 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_shown", "" );
377 osc_show_gui ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
381 /* FIXME: detect errors */
383 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
393 kill( gui_pid, SIGTERM );
398 osc_hide_gui ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
402 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" );
404 /* FIXME: detect errors */
406 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
412 osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
414 const char *new_path = &argv[0]->s;
415 const char *display_name = &argv[1]->s;
416 const char *client_id = &argv[2]->s;
421 nsm_client_id = strdup( client_id );
423 if ( nsm_display_name )
424 free( nsm_display_name );
426 nsm_display_name = strdup( display_name );
430 mkdir( new_path, 0777 );
434 asprintf( &new_filename, "%s/%s", new_path, CONFIG_FILE_NAME );
438 if ( 0 == stat( new_filename, &st ) )
440 if ( open( new_path ) )
445 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Could not open file" );
449 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" );
457 free( project_file );
459 project_file = strdup( new_path );
463 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
466 nsm_proxy->update( gui_addr );
476 osc_label ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
478 nsm_proxy->label( &argv[0]->s );
484 osc_save_signal ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
486 nsm_proxy->save_signal( argv[0]->i );
492 osc_start ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
494 snapshot( project_file );
496 if ( nsm_proxy->start( &argv[0]->s, &argv[1]->s ) )
505 osc_kill ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
513 osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
515 lo_address to = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
517 nsm_proxy->update( to );
527 signal_handler ( int x )
535 signal( SIGHUP, signal_handler );
536 signal( SIGINT, signal_handler );
537 // signal( SIGQUIT, signal_handler );
538 // signal( SIGSEGV, signal_handler );
539 // signal( SIGPIPE, signal_handler );
540 signal( SIGTERM, signal_handler );
545 init_osc ( const char *osc_port )
547 losrv = lo_server_new( osc_port, NULL );
550 char *url = lo_server_get_url(losrv);
551 printf("OSC: %s\n",url);
555 lo_server_add_method( losrv, "/nsm/client/save", "", osc_save, NULL );
556 lo_server_add_method( losrv, "/nsm/client/open", "sss", osc_open, NULL );
557 lo_server_add_method( losrv, "/nsm/client/show_optional_gui", "", osc_show_gui, NULL );
558 lo_server_add_method( losrv, "/nsm/client/hide_optional_gui", "", osc_hide_gui, NULL );
559 lo_server_add_method( losrv, "/error", "sis", osc_announce_error, NULL );
560 lo_server_add_method( losrv, "/reply", "ssss", osc_announce_reply, NULL );
563 lo_server_add_method( losrv, "/nsm/proxy/label", "s", osc_label, NULL );
564 lo_server_add_method( losrv, "/nsm/proxy/save_signal", "i", osc_save_signal, NULL );
565 lo_server_add_method( losrv, "/nsm/proxy/kill", "", osc_kill, NULL );
566 lo_server_add_method( losrv, "/nsm/proxy/start", "ss", osc_start, NULL );
567 lo_server_add_method( losrv, "/nsm/proxy/update", "", osc_update, NULL );
576 DMESSAGE( "Killing GUI" );
578 kill( gui_pid, SIGTERM );
587 void handle_sigchld ( )
592 pid_t pid = waitpid(-1, &status, WNOHANG);
597 if ( pid == gui_pid )
599 lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/nsm/client/gui_is_hidden", "" );
607 /* otherwise, it was our proxied process that died, so we should die too */
608 printf( "proxied process died... nsm-proxy dying too\n" );
615 main ( int argc, char **argv )
621 sigemptyset( &mask );
622 sigaddset( &mask, SIGCHLD );
624 sigprocmask(SIG_BLOCK, &mask, NULL );
626 signal_fd = signalfd( -1, &mask, SFD_NONBLOCK );
628 nsm_proxy = new NSM_Proxy();
632 const char *nsm_url = getenv( "NSM_URL" );
636 announce( nsm_url, APP_TITLE, argv[0] );
640 fprintf( stderr, "Could not register as NSM client.\n" );
645 struct signalfd_siginfo fdsi;
647 /* listen for sigchld signals and process OSC messages forever */
650 ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo));
652 if (s == sizeof(struct signalfd_siginfo))
654 if (fdsi.ssi_signo == SIGCHLD)
658 lo_server_recv_noblock( losrv, 500 );