Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2542 lines
65KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */
  3. /* Copyright (C) 2020- Nils Hilbricht */
  4. /* */
  5. /* This file is part of New-Session-Manager */
  6. /* */
  7. /* New-Session-Manager is free software: you can redistribute it and/or modify */
  8. /* it under the terms of the GNU General Public License as published by */
  9. /* the Free Software Foundation, either version 3 of the License, or */
  10. /* (at your option) any later version. */
  11. /* */
  12. /* New-Session-Manager is distributed in the hope that it will be useful, */
  13. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  14. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  15. /* GNU General Public License for more details. */
  16. /* */
  17. /* You should have received a copy of the GNU General Public License */
  18. /* along with New-Session-Manager. If not, see <https://www.gnu.org/licenses/>.*/
  19. /*******************************************************************************/
  20. #define __MODULE__ "nsmd"
  21. //debug.c has only one function that gets used multiple times by debug.h and for logging and printing
  22. #include "debug.h"
  23. #ifndef _GNU_SOURCE
  24. #define _GNU_SOURCE
  25. #endif
  26. #include <errno.h>
  27. #include <string.h>
  28. #include <list>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <sys/types.h>
  33. #include <signal.h>
  34. #include <sys/signalfd.h>
  35. #include <sys/stat.h>
  36. #include <sys/wait.h>
  37. #include <unistd.h>
  38. #include <time.h>
  39. #include <libgen.h>
  40. #include <dirent.h>
  41. #include <ftw.h>
  42. #include <list>
  43. #include <getopt.h>
  44. #include <sys/time.h>
  45. #include "Endpoint.hpp"
  46. /* for locking */
  47. #include "file.h"
  48. #include <map>
  49. #include <string>
  50. #include <algorithm>
  51. #pragma GCC diagnostic ignored "-Wunused-parameter"
  52. #pragma GCC diagnostic ignored "-Wunused-result"
  53. static OSC::Endpoint *osc_server;
  54. static lo_address gui_addr;
  55. static bool gui_is_active = false;
  56. static int signal_fd;
  57. static int session_lock_fd = 0;
  58. static char *session_root;
  59. #define NSM_API_VERSION_MAJOR 1
  60. #define NSM_API_VERSION_MINOR 2
  61. #define ERR_OK 0
  62. #define ERR_GENERAL_ERROR -1
  63. #define ERR_INCOMPATIBLE_API -2
  64. #define ERR_BLACKLISTED -3
  65. #define ERR_LAUNCH_FAILED -4
  66. #define ERR_NO_SUCH_FILE -5
  67. #define ERR_NO_SESSION_OPEN -6
  68. #define ERR_UNSAVED_CHANGES -7
  69. #define ERR_NOT_NOW -8
  70. #define ERR_BAD_PROJECT -9
  71. #define ERR_CREATE_FAILED -10
  72. #define ERR_SESSION_LOCKED -11
  73. #define ERR_OPERATION_PENDING -12
  74. #define APP_TITLE "New Session Manager"
  75. enum {
  76. COMMAND_NONE = 0,
  77. COMMAND_QUIT,
  78. COMMAND_KILL,
  79. COMMAND_SAVE,
  80. COMMAND_OPEN,
  81. COMMAND_START,
  82. COMMAND_CLOSE,
  83. COMMAND_DUPLICATE,
  84. COMMAND_NEW
  85. };
  86. static int pending_operation = COMMAND_NONE;
  87. static void wait ( long );
  88. #define GUIMSG( fmt, args... ) \
  89. { \
  90. MESSAGE( fmt, ## args ); \
  91. if ( gui_is_active ) \
  92. { \
  93. char *s;\
  94. asprintf( &s, fmt, ## args );\
  95. osc_server->send( gui_addr, "/nsm/gui/server/message", s);\
  96. free(s);\
  97. }\
  98. }
  99. struct Client
  100. {
  101. private:
  102. int _reply_errcode;
  103. char *_reply_message;
  104. int _pending_command;
  105. struct timeval _command_sent_time;
  106. bool _gui_visible;
  107. char *_label;
  108. public:
  109. lo_address addr=0; /* */
  110. char *name; /* client application name */
  111. char *executable_path; /* path to client executable */
  112. int pid; /* PID of client process */
  113. float progress; /* */
  114. bool active; /* NSM capable: client has registered via announce */
  115. //bool stopped; /* the client quit, but not because we told it to--user still has to decide to remove it from the session */
  116. char *client_id; /* short part of client ID */
  117. char *capabilities; /* client capabilities... will be null for dumb clients */
  118. bool dirty; /* flag for client self-reported dirtiness */
  119. bool pre_existing;
  120. const char *status;
  121. int launch_error; /* v1.4, leads to status for executable not found, permission denied etc. */
  122. char *name_with_id; /* v1.4, client.nABC */
  123. const char *label ( void ) const { return _label; }
  124. void label ( const char *l )
  125. {
  126. if ( _label )
  127. free( _label );
  128. if ( l )
  129. _label = strdup( l );
  130. else
  131. _label = NULL;
  132. }
  133. bool gui_visible ( void ) const
  134. {
  135. return _gui_visible;
  136. }
  137. void gui_visible ( bool b )
  138. {
  139. _gui_visible = b;
  140. }
  141. bool
  142. has_error ( void ) const
  143. {
  144. return _reply_errcode != 0;
  145. }
  146. int
  147. error_code ( void ) const
  148. {
  149. return _reply_errcode;
  150. }
  151. const char * message ( void )
  152. {
  153. return _reply_message;
  154. }
  155. void
  156. set_reply ( int errcode, const char *message )
  157. {
  158. if ( _reply_message )
  159. free( _reply_message );
  160. _reply_message = strdup( message );
  161. _reply_errcode = errcode;
  162. }
  163. bool reply_pending ( void )
  164. {
  165. return _pending_command != COMMAND_NONE;
  166. }
  167. bool is_dumb_client ( void )
  168. {
  169. return capabilities == NULL;
  170. }
  171. void pending_command ( int command )
  172. {
  173. gettimeofday( &_command_sent_time, NULL );
  174. _pending_command = command;
  175. }
  176. double milliseconds_since_last_command ( void ) const
  177. {
  178. struct timeval now;
  179. gettimeofday( &now, NULL );
  180. double elapsedms = ( now.tv_sec - _command_sent_time.tv_sec ) * 1000.0;
  181. elapsedms += ( now.tv_usec - _command_sent_time.tv_usec ) / 1000.0;
  182. return elapsedms;
  183. }
  184. int pending_command ( void )
  185. {
  186. return _pending_command;
  187. }
  188. // capability should be enclosed in colons. I.e. ":switch:"
  189. bool
  190. is_capable_of ( const char *capability ) const
  191. {
  192. return capabilities &&
  193. strstr( capabilities, capability );
  194. }
  195. Client ( )
  196. {
  197. _label = 0;
  198. _gui_visible = true;
  199. _reply_errcode = 0;
  200. _reply_message = 0;
  201. pid = 0;
  202. progress = -0;
  203. _pending_command = 0;
  204. active = false;
  205. client_id = 0;
  206. capabilities = 0;
  207. name = 0;
  208. executable_path = 0;
  209. pre_existing = false;
  210. launch_error = 0;
  211. dirty = 0;
  212. status = 0;
  213. name_with_id = 0;
  214. }
  215. ~Client ( )
  216. {
  217. if ( name )
  218. free(name);
  219. if (executable_path)
  220. free(executable_path);
  221. if (client_id)
  222. free(client_id);
  223. if (capabilities)
  224. free(capabilities);
  225. if (name_with_id)
  226. free(name_with_id);
  227. name = executable_path = client_id = capabilities = name_with_id = NULL;
  228. }
  229. };
  230. static std::list< Client* > client;
  231. /* helper macros for defining OSC handlers */
  232. #define OSC_NAME( name ) osc_ ## name
  233. // #define OSCDMSG() DMESSAGE( "Got OSC message: %s", path );
  234. #define OSC_HANDLER( name ) static int OSC_NAME( name ) ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  235. static char *session_path = NULL;
  236. static char *session_name = NULL;
  237. bool
  238. clients_have_errors ( )
  239. {
  240. for ( std::list<Client*>::const_iterator i = client.begin();
  241. i != client.end();
  242. ++i )
  243. if ( (*i)->active && (*i)->has_error() )
  244. return true;
  245. return false;
  246. }
  247. Client *
  248. get_client_by_pid ( int pid )
  249. {
  250. std::list<Client*> *cl = &client;
  251. for ( std::list<Client*>::const_iterator i = cl->begin();
  252. i != cl->end();
  253. ++i )
  254. if ( (*i)->pid == pid )
  255. return *i;
  256. return NULL;
  257. }
  258. void clear_clients ( void )
  259. {
  260. std::list<Client*> *cl = &client;
  261. for ( std::list<Client*>::iterator i = cl->begin();
  262. i != cl->end();
  263. ++i )
  264. {
  265. delete *i;
  266. i = cl->erase( i );
  267. }
  268. }
  269. void
  270. handle_client_process_death ( int pid )
  271. {
  272. Client *c = get_client_by_pid( (int)pid );
  273. if ( c )
  274. {
  275. //There is a difference if a client quit on its own, e.g. via a menu or window manager,
  276. //or if the server send SIGTERM as quit signal. Both cases are equally valid.
  277. //We only check the case to print a different log message
  278. bool dead_because_we_said = ( c->pending_command() == COMMAND_KILL ||
  279. c->pending_command() == COMMAND_QUIT );
  280. if ( dead_because_we_said )
  281. {
  282. GUIMSG( "Client %s terminated by server instruction.", c->name_with_id );
  283. }
  284. else
  285. {
  286. GUIMSG( "Client %s terminated itself.", c->name_with_id );
  287. }
  288. //Decide if the client terminated or if removed from the session
  289. if ( c->pending_command() == COMMAND_QUIT )
  290. {
  291. c->status = "removed";
  292. if ( gui_is_active )
  293. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  294. client.remove(c); //This will not remove the clients save data
  295. delete c;
  296. }
  297. else
  298. {
  299. c->status = "stopped";
  300. if ( gui_is_active )
  301. {
  302. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  303. if ( c->launch_error )
  304. {
  305. /* NSM API treats the stopped status as switch. You can only remove stopped.
  306. * Furthermore the GUI will change its client-buttons.
  307. * In consequence we cannot add an arbitrary "launch-error" status.
  308. * Compatible compromise is to use the label field to relay info the user,
  309. * which was the goal. There is nothing we can do about a failed launch anyway.
  310. */
  311. GUIMSG("Client %s had a launch error.", c->name_with_id);
  312. osc_server->send( gui_addr, "/nsm/gui/client/label", c->client_id, "launch error!" ); //do not set the client objects label.
  313. }
  314. }
  315. }
  316. c->pending_command( COMMAND_NONE );
  317. c->active = false;
  318. c->pid = 0;
  319. }
  320. }
  321. void handle_sigchld ( )
  322. {
  323. // compare waitpid(2)
  324. for ( ;; )
  325. {
  326. int status = 1; // make it not NULL to enable information storage in status
  327. pid_t pid = waitpid(-1, &status, WNOHANG); //-1 meaning wait for any child process. pid_t is signed integer
  328. if (pid <= 0)
  329. {
  330. break; // no child process has ended this loop. Check again.
  331. }
  332. else
  333. {
  334. //One child process has stopped. Find which and figure out the stop-conditions
  335. Client *c;
  336. c = get_client_by_pid( pid );
  337. if ( c )
  338. {
  339. //The following will not trigger with normal crashes, e.g. segfaults or python tracebacks
  340. if ( WIFEXITED( status ) ) // returns true if the child terminated normally
  341. if ( WEXITSTATUS( status ) == 255 ) // as given by exit(-1) in launch()
  342. c->launch_error = true;
  343. }
  344. // Call even if Client was already null. This will check itself again and was expected
  345. // to be called for the majority of nsmds development
  346. handle_client_process_death( pid );
  347. }
  348. }
  349. }
  350. int
  351. path_is_valid ( const char *path )
  352. {
  353. char *s;
  354. asprintf( &s, "/%s/", path );
  355. int r = strstr( s, "/../" ) == NULL;
  356. free( s );
  357. return r;
  358. }
  359. int
  360. mkpath ( const char *path, bool create_final_directory )
  361. {
  362. char *p = strdup( path );
  363. char *i = p + 1;
  364. while ( ( i = index( i, '/' ) ) )
  365. {
  366. *i = 0;
  367. struct stat st;
  368. if ( stat( p, &st ) )
  369. {
  370. if ( mkdir( p, 0711 ) )
  371. {
  372. free( p );
  373. return -1;
  374. }
  375. }
  376. *i = '/';
  377. i++;
  378. }
  379. if ( create_final_directory )
  380. {
  381. if ( mkdir( p, 0711 ) )
  382. {
  383. free( p );
  384. return -1;
  385. }
  386. }
  387. free( p );
  388. return 0;
  389. }
  390. void
  391. set_name ( const char *name )
  392. {
  393. if ( session_name )
  394. free( session_name );
  395. char *s = strdup( name );
  396. session_name = strdup( basename( s ) );
  397. free( s );
  398. }
  399. bool
  400. address_matches ( lo_address addr1, lo_address addr2 )
  401. {
  402. /* char *url1 = lo_address_get_url( addr1 ); */
  403. /* char *url2 = lo_address_get_url( addr2 ); */
  404. char *url1 = strdup( lo_address_get_port( addr1 ) );
  405. char *url2 = strdup(lo_address_get_port( addr2 ) );
  406. bool r = !strcmp( url1, url2 );
  407. free( url1 );
  408. free( url2 );
  409. return r;
  410. }
  411. Client *
  412. get_client_by_id ( std::list<Client*> *cl, const char *id )
  413. {
  414. for ( std::list<Client*>::const_iterator i = cl->begin();
  415. i != cl->end();
  416. ++i )
  417. if ( !strcmp( (*i)->client_id, id ) )
  418. return *i;
  419. return NULL;
  420. }
  421. Client *
  422. get_client_by_name_and_id ( std::list<Client*> *cl, const char *name, const char *id )
  423. {
  424. for ( std::list<Client*>::const_iterator i = cl->begin();
  425. i != cl->end();
  426. ++i )
  427. if ( !strcmp( (*i)->client_id, id ) &&
  428. ! strcmp( (*i)->name, name ) )
  429. return *i;
  430. return NULL;
  431. }
  432. Client *
  433. get_client_by_address ( lo_address addr )
  434. {
  435. for ( std::list<Client*>::iterator i = client.begin();
  436. i != client.end();
  437. ++i )
  438. if ( (*i)->addr && address_matches( (*i)->addr, addr ) )
  439. return *i;
  440. return NULL;
  441. }
  442. char *
  443. generate_client_id ( void )
  444. {
  445. /* Before v1.4 this returned "n" + 4 random upper-case letters, which could lead to collisions.
  446. We changed behaviour to still generate 4 letters, but check for collision with existing IDs.
  447. Loaded client IDs are not checked, just copied from session.nsm because loading happens before
  448. any generation of new clients. Loaded clients are part of further checks of course.
  449. There is a theoretical limit when all 26^4 IDs are in use which will lead to an infinite loop
  450. of generation. We risk to leave this unhandled. */
  451. char id_str[6];
  452. id_str[0] = 'n';
  453. id_str[5] = 0;
  454. while ( true )
  455. {
  456. for ( int i = 1; i < 5; i++ )
  457. id_str[i] = 'A' + (rand() % 25);
  458. if ( get_client_by_id(&client, id_str )==NULL ) // found a free id
  459. break;
  460. }
  461. return strdup(id_str);
  462. }
  463. bool
  464. replies_still_pending ( void )
  465. {
  466. for ( std::list<Client*>::const_iterator i = client.begin();
  467. i != client.end();
  468. ++i )
  469. if ( (*i)->active && (*i)->reply_pending() )
  470. return true;
  471. return false;
  472. }
  473. int
  474. number_of_reponsive_clients ( void )
  475. {
  476. /* This was renamed from number_of_active_clients in version 1.4 to reflect
  477. * that not only active==true clients are in a state where waiting has ended, but also clients
  478. * that never started. It is used in wait_for_announce only, which added a 5000ms delay to startup
  479. *
  480. * We are sadly unable to distinguish between a client that has a slow announce and a client
  481. * without NSM-support. However, this is mitgated by nsm-proxy which is a reliable indicator
  482. * that this program will never announce (or rather nsm-proxy announces normally).
  483. */
  484. int responsive = 0;
  485. for ( std::list<Client*>::const_iterator i = client.begin(); i != client.end(); ++i )
  486. {
  487. //Optimisation: Clients that never launched (e.g. file not found) will be checked many times/seconds here. We skip them by counting them
  488. if ( (*i)->active || (*i)->launch_error )
  489. responsive++;
  490. }
  491. return responsive;
  492. }
  493. void
  494. wait_for_announce ( void )
  495. {
  496. GUIMSG( "Waiting for announce messages from clients" );
  497. int n = 5 * 1000;
  498. long unsigned int active;
  499. while ( n > 0 )
  500. {
  501. n -= 100;
  502. wait(100);
  503. active = number_of_reponsive_clients();
  504. if ( client.size() == active )
  505. break;
  506. }
  507. GUIMSG( "Done. %lu out of %lu clients announced (or failed to launch) within the initialization grace period",
  508. active, (long unsigned)client.size() );
  509. }
  510. void
  511. wait_for_replies ( void )
  512. {
  513. GUIMSG( "Waiting for clients to reply to commands" );
  514. int n = 60 * 1000; /* 60 seconds */
  515. while ( n )
  516. {
  517. n -= 100;
  518. wait(100);
  519. if ( ! replies_still_pending() )
  520. break;
  521. }
  522. GUIMSG( "Done waiting" );
  523. /* FIXME: do something about unresponsive clients */
  524. }
  525. char *
  526. get_client_project_path ( const char *session_path, Client *c )
  527. {
  528. char *client_project_path;
  529. asprintf( &client_project_path, "%s/%s.%s", session_path, c->name, c->client_id );
  530. return client_project_path;
  531. }
  532. bool
  533. launch ( const char *executable, const char *client_id )
  534. {
  535. Client *c;
  536. if ( !client_id || !( c = get_client_by_id( &client, client_id ) ) )
  537. {
  538. c = new Client();
  539. c->executable_path = strdup( executable );
  540. {
  541. char *s = strdup( c->executable_path );
  542. c->name = strdup( basename( s ) );
  543. free( s );
  544. }
  545. if ( client_id )
  546. c->client_id = strdup( client_id );
  547. else
  548. c->client_id = generate_client_id();
  549. asprintf( &c->name_with_id, "%s.%s", c->name, c->client_id );
  550. client.push_back( c );
  551. }
  552. char * url = osc_server->url();
  553. int pid;
  554. if ( ! (pid = fork()) )
  555. {
  556. //This is code of the child process. It will be executed after launch() has finished
  557. GUIMSG( "Launching %s", executable );
  558. char *args[] = { strdup( executable ), NULL };
  559. setenv( "NSM_URL", url, 1 );
  560. /* Ensure the launched process can receive SIGCHLD */
  561. /* Unblocking SIGCHLD here does NOT unblock it for nsmd itself */
  562. sigset_t mask;
  563. sigemptyset( &mask );
  564. sigaddset( &mask, SIGCHLD );
  565. sigprocmask(SIG_UNBLOCK, &mask, NULL );
  566. if ( -1 == execvp( executable, args ) )
  567. {
  568. /* The program was not started. Causes: not installed on the current system, and the
  569. * session was transferred from another system, or permission denied (no executable flag)
  570. * Since we are running in a forked child process Client c does exist, but points to
  571. * a memory copy, not the real client. So we can't set any error code or status in the
  572. * client object. Instead we check the exit return code in handle_sigchld() and set the
  573. * bool client->launch_error to true.
  574. */
  575. WARNING( "Error starting process %s: %s", executable, strerror( errno ) );
  576. exit(-1); //-1 later parsed as 255
  577. }
  578. }
  579. //This is code of the parent process. It is executed right at this point, before the child.
  580. c->pending_command( COMMAND_START );
  581. c->pid = pid;
  582. MESSAGE( "Process %s has pid: %i", executable, pid ); //We do not have a name yet, use executable
  583. c->status = "launch";
  584. if ( gui_is_active )
  585. {
  586. //At this point we do not know if launched program will start or fail
  587. //And we do not know if it has nsm-support or not. This will be decided if it announces.
  588. osc_server->send( gui_addr, "/nsm/gui/client/new", c->client_id, c->name );
  589. osc_server->send( gui_addr, "/nsm/gui/client/label", c->client_id, "" ); //clear label from potential previous-and-fixed launch error
  590. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  591. }
  592. return true;
  593. }
  594. void
  595. command_client_to_save ( Client *c )
  596. {
  597. if ( c->active )
  598. {
  599. MESSAGE( "Telling %s to save", c->name_with_id );
  600. osc_server->send( c->addr, "/nsm/client/save" );
  601. c->pending_command( COMMAND_SAVE );
  602. c->status = "save";
  603. if ( gui_is_active )
  604. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  605. }
  606. else if ( c->is_dumb_client() && c->pid )
  607. {
  608. // this is a dumb client...
  609. c->status = "noop";
  610. if ( gui_is_active )
  611. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  612. }
  613. }
  614. void command_client_to_switch ( Client *c, const char *new_client_id )
  615. {
  616. char *old_client_id = c->client_id;
  617. c->client_id = strdup( new_client_id );
  618. char *client_project_path = get_client_project_path( session_path, c );
  619. MESSAGE( "Commanding %s to switch \"%s\"", c->name_with_id, client_project_path );
  620. char *full_client_id;
  621. asprintf( &full_client_id, "%s.%s", c->name, c->client_id );
  622. osc_server->send( c->addr, "/nsm/client/open", client_project_path, session_name, full_client_id );
  623. free( full_client_id );
  624. free( client_project_path );
  625. c->pending_command( COMMAND_OPEN );
  626. c->status = "switch";
  627. if ( gui_is_active )
  628. {
  629. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  630. osc_server->send( gui_addr, "/nsm/gui/client/switch", old_client_id, c->client_id );
  631. }
  632. free( old_client_id );
  633. }
  634. void
  635. purge_inactive_clients ( )
  636. {
  637. for ( std::list<Client*>::iterator i = client.begin();
  638. i != client.end();
  639. ++i )
  640. {
  641. if ( ! (*i)->active )
  642. {
  643. (*i)->status = "removed";
  644. if ( gui_is_active )
  645. osc_server->send( gui_addr, "/nsm/gui/client/status", (*i)->client_id, (*i)->status );
  646. delete *i;
  647. i = client.erase( i );
  648. }
  649. }
  650. }
  651. bool
  652. process_is_running ( int pid )
  653. {
  654. if ( 0 == kill( pid, 0 ) )
  655. {
  656. return true;
  657. }
  658. else if ( ESRCH == errno )
  659. {
  660. return false;
  661. }
  662. return false;
  663. }
  664. void
  665. purge_dead_clients ( )
  666. {
  667. std::list<Client*> tmp( client );
  668. for ( std::list<Client*>::const_iterator i = tmp.begin();
  669. i != tmp.end();
  670. ++i )
  671. {
  672. const Client *c = *i;
  673. if ( c->pid )
  674. {
  675. if ( ! process_is_running( c->pid ) )
  676. handle_client_process_death( c->pid );
  677. }
  678. }
  679. }
  680. /************************/
  681. /* OSC Message Handlers */
  682. /************************/
  683. OSC_HANDLER( add )
  684. {
  685. if ( ! session_path )
  686. {
  687. osc_server->send( lo_message_get_source( msg ), "/error", path,
  688. ERR_NO_SESSION_OPEN,
  689. "Cannot add to session because no session is loaded." );
  690. return 0;
  691. }
  692. if ( strchr( &argv[0]->s, '/' ) )
  693. {
  694. osc_server->send( lo_message_get_source( msg ), "/error", path,
  695. ERR_LAUNCH_FAILED,
  696. "Absolute paths are not permitted. Clients must be in $PATH" );
  697. return 0;
  698. }
  699. if ( ! launch( &argv[0]->s, NULL ) )
  700. {
  701. osc_server->send( lo_message_get_source( msg ), "/error", path,
  702. ERR_LAUNCH_FAILED,
  703. "Failed to launch process!" );
  704. }
  705. else
  706. {
  707. osc_server->send( lo_message_get_source( msg ), "/reply", path, "Launched." );
  708. }
  709. return 0;
  710. }
  711. OSC_HANDLER( announce )
  712. {
  713. const char *client_name = &argv[0]->s;
  714. const char *capabilities = &argv[1]->s;
  715. const char *executable_path = &argv[2]->s;
  716. int major = argv[3]->i;
  717. int minor = argv[4]->i;
  718. int pid = argv[5]->i;
  719. GUIMSG( "Got announce from %s", client_name );
  720. if ( ! session_path )
  721. {
  722. osc_server->send( lo_message_get_source( msg ), "/error",
  723. path,
  724. ERR_NO_SESSION_OPEN,
  725. "Sorry, but there's no session open for this application to join." );
  726. return 0;
  727. }
  728. bool expected_client = false;
  729. Client *c = NULL;
  730. for ( std::list<Client*>::iterator i = client.begin();
  731. i != client.end();
  732. ++i )
  733. {
  734. if ( ! strcmp( (*i)->executable_path, executable_path ) &&
  735. ! (*i)->active &&
  736. (*i)->pending_command() == COMMAND_START )
  737. {
  738. // I think we've found the slot we were looking for.
  739. MESSAGE( "Client %s was expected.", (*i)->name );
  740. c = *i;
  741. break;
  742. }
  743. }
  744. if ( ! c )
  745. {
  746. c = new Client();
  747. c->executable_path = strdup( executable_path );
  748. c->client_id = generate_client_id();
  749. }
  750. else
  751. expected_client = true;
  752. if ( major > NSM_API_VERSION_MAJOR )
  753. {
  754. MESSAGE( "Client %s is using incompatible and more recent API version %i.%i", c->name_with_id, major, minor );
  755. osc_server->send( lo_message_get_source( msg ), "/error",
  756. path,
  757. ERR_INCOMPATIBLE_API,
  758. "Server is using an incompatible API version." );
  759. return 0;
  760. }
  761. c->pid = pid;
  762. c->capabilities = strdup( capabilities );
  763. c->addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  764. c->name = strdup( client_name );
  765. c->active = true;
  766. asprintf( &c->name_with_id, "%s.%s", c->name, c->client_id );
  767. MESSAGE( "Process %s has pid: %i", c->name_with_id, pid );
  768. if ( ! expected_client )
  769. client.push_back( c );
  770. MESSAGE( "The client \"%s\" at \"%s\" informs us it's ready to receive commands.", &argv[0]->s, lo_address_get_url( c->addr ) );
  771. osc_server->send( lo_message_get_source( msg ), "/reply",
  772. path,
  773. expected_client ?
  774. "Howdy, what took you so long?" :
  775. "Well hello, stranger. Welcome to the party.",
  776. APP_TITLE,
  777. ":server-control:broadcast:optional-gui:" );
  778. c->status = "open";
  779. if ( gui_is_active )
  780. {
  781. osc_server->send( gui_addr, "/nsm/gui/client/new", c->client_id, c->name );
  782. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  783. if ( c->is_capable_of( ":optional-gui:" ) )
  784. osc_server->send( gui_addr, "/nsm/gui/client/has_optional_gui", c->client_id );
  785. }
  786. {
  787. char *full_client_id;
  788. asprintf( &full_client_id, "%s.%s", c->name, c->client_id );
  789. char *client_project_path = get_client_project_path( session_path, c );
  790. osc_server->send( lo_message_get_source( msg ), "/nsm/client/open", client_project_path, session_name, full_client_id );
  791. c->pending_command( COMMAND_OPEN );
  792. free( full_client_id );
  793. free( client_project_path );
  794. }
  795. return 0;
  796. }
  797. void
  798. save_session_file ( )
  799. {
  800. char *session_file = NULL;
  801. asprintf( &session_file, "%s/session.nsm", session_path );
  802. FILE *fp = fopen( session_file, "w+" );
  803. free( session_file );
  804. /* FIXME: handle errors. */
  805. for ( std::list<Client*>::iterator i = client.begin();
  806. i != client.end();
  807. ++i )
  808. {
  809. fprintf( fp, "%s:%s:%s\n", (*i)->name, (*i)->executable_path, (*i)->client_id );
  810. }
  811. fclose( fp );
  812. }
  813. Client *
  814. client_by_name ( const char *name,
  815. std::list<Client*> *cl )
  816. {
  817. for ( std::list<Client*>::iterator i = cl->begin();
  818. i != cl->end();
  819. ++i )
  820. {
  821. if ( !strcmp( name, (*i)->name ) )
  822. return *i;
  823. }
  824. return NULL;
  825. }
  826. bool
  827. dumb_clients_are_alive ( )
  828. {
  829. std::list<Client*> *cl = &client;
  830. for ( std::list<Client*>::iterator i = cl->begin();
  831. i != cl->end();
  832. ++i )
  833. {
  834. if ( (*i)->is_dumb_client() && (*i)->pid > 0 )
  835. {
  836. MESSAGE( "Waiting for %s", (*i)->name_with_id ); //This replaced the Loop 1, Loop 2 ... 60 message from wait_for_dumb_clients_to_die where you couldn't see which client actually was hanging
  837. return true;
  838. }
  839. }
  840. return false;
  841. }
  842. void
  843. wait_for_dumb_clients_to_die ( )
  844. {
  845. struct signalfd_siginfo fdsi;
  846. GUIMSG( "Waiting for any dumb clients to die." );
  847. for ( int i = 0; i < 6; i++ )
  848. {
  849. if ( ! dumb_clients_are_alive() )
  850. break;
  851. ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo));
  852. if (s == sizeof(struct signalfd_siginfo))
  853. {
  854. if (fdsi.ssi_signo == SIGCHLD)
  855. handle_sigchld();
  856. }
  857. usleep( 50000 );
  858. }
  859. GUIMSG( "Done waiting" );
  860. /* FIXME: give up on remaining clients and purge them */
  861. }
  862. bool
  863. killed_clients_are_alive ( )
  864. {
  865. std::list<Client*> *cl = &client;
  866. for ( std::list<Client*>::iterator i = cl->begin();
  867. i != cl->end();
  868. ++i )
  869. {
  870. if ( ( (*i)->pending_command() == COMMAND_QUIT ||
  871. (*i)->pending_command() == COMMAND_KILL ) &&
  872. (*i)->pid > 0 )
  873. {
  874. MESSAGE( "Waiting for %s", (*i)->name_with_id ); //This replaced the Loop 1, Loop 2 ... 60 message from wait_for_killed_clients_to_die where you couldn't see which client actually was hanging
  875. return true;
  876. }
  877. }
  878. return false;
  879. }
  880. void
  881. wait_for_killed_clients_to_die ( )
  882. {
  883. struct signalfd_siginfo fdsi;
  884. MESSAGE( "Waiting for killed clients to die." );
  885. for ( int i = 0; i < 60; i++ )
  886. {
  887. if ( ! killed_clients_are_alive() )
  888. goto done;
  889. ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo));
  890. if (s == sizeof(struct signalfd_siginfo))
  891. {
  892. if (fdsi.ssi_signo == SIGCHLD)
  893. handle_sigchld();
  894. }
  895. purge_dead_clients();
  896. /* check OSC so we can get /progress messages. */
  897. osc_server->check();
  898. sleep(1);
  899. }
  900. WARNING( "Killed clients are still alive" );
  901. return;
  902. done:
  903. MESSAGE( "All clients have died." );
  904. }
  905. void
  906. command_all_clients_to_save ( )
  907. {
  908. if ( session_path )
  909. {
  910. GUIMSG( "Commanding attached clients to save." );
  911. for ( std::list<Client*>::iterator i = client.begin();
  912. i != client.end();
  913. ++i )
  914. {
  915. command_client_to_save( *i );
  916. }
  917. wait_for_replies();
  918. save_session_file();
  919. }
  920. }
  921. void
  922. command_client_to_stop ( Client *c )
  923. {
  924. GUIMSG( "Stopping client %s", c->name_with_id );
  925. if ( c->pid > 0 )
  926. {
  927. c->pending_command( COMMAND_KILL );
  928. kill( c->pid, SIGTERM );
  929. c->status = "stopped";
  930. if ( gui_is_active )
  931. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  932. }
  933. }
  934. void
  935. command_client_to_quit ( Client *c )
  936. {
  937. MESSAGE( "Commanding %s to quit", c->name_with_id );
  938. if ( c->active )
  939. {
  940. c->pending_command( COMMAND_QUIT );
  941. kill( c->pid, SIGTERM );
  942. c->status = "quit";
  943. if ( gui_is_active )
  944. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  945. }
  946. else if ( c->is_dumb_client() )
  947. {
  948. if ( c->pid > 0 )
  949. {
  950. c->status = "quit";
  951. if ( gui_is_active )
  952. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  953. /* should be kill? */
  954. c->pending_command( COMMAND_QUIT );
  955. // this is a dumb client... try and kill it
  956. kill( c->pid, SIGTERM );
  957. }
  958. else
  959. {
  960. c->status = "removed";
  961. if ( gui_is_active )
  962. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  963. }
  964. }
  965. }
  966. void
  967. close_session ( )
  968. {
  969. if ( ! session_path )
  970. return;
  971. for ( std::list<Client*>::iterator i = client.begin();
  972. i != client.end();
  973. ++i )
  974. {
  975. command_client_to_quit( *i );
  976. }
  977. wait_for_killed_clients_to_die();
  978. purge_inactive_clients();
  979. clear_clients();
  980. if ( session_path )
  981. {
  982. char *session_lock;
  983. asprintf( &session_lock, "%s/.lock", session_path );
  984. release_lock( &session_lock_fd, session_lock );
  985. free(session_lock);
  986. free(session_path);
  987. session_path = NULL;
  988. free(session_name);
  989. session_name = NULL;
  990. }
  991. if ( gui_is_active )
  992. {
  993. osc_server->send( gui_addr, "/nsm/gui/session/name", "", "" );
  994. }
  995. }
  996. void
  997. tell_client_session_is_loaded( Client *c )
  998. {
  999. if ( c->active )
  1000. //!c->is_dumb_client() )
  1001. {
  1002. MESSAGE( "Telling client %s that session is loaded.", c->name_with_id );
  1003. osc_server->send( c->addr, "/nsm/client/session_is_loaded" );
  1004. }
  1005. }
  1006. void
  1007. tell_all_clients_session_is_loaded ( void )
  1008. {
  1009. MESSAGE( "Telling all clients that session is loaded..." );
  1010. for ( std::list<Client*>::iterator i = client.begin();
  1011. i != client.end();
  1012. ++i )
  1013. {
  1014. tell_client_session_is_loaded( *i );
  1015. }
  1016. }
  1017. int
  1018. load_session_file ( const char * path )
  1019. {
  1020. char *session_file = NULL;
  1021. asprintf( &session_file, "%s/session.nsm", path );
  1022. char *session_lock = NULL;
  1023. asprintf( &session_lock, "%s/.lock", path );
  1024. if ( ! acquire_lock( &session_lock_fd, session_lock ) )
  1025. {
  1026. free( session_file );
  1027. free( session_lock );
  1028. WARNING( "Session is locked by another process" );
  1029. return ERR_SESSION_LOCKED;
  1030. }
  1031. FILE *fp;
  1032. if ( ! ( fp = fopen( session_file, "r" ) ) )
  1033. {
  1034. free( session_file );
  1035. return ERR_CREATE_FAILED;
  1036. }
  1037. free( session_file );
  1038. session_path = strdup( path );
  1039. set_name( path );
  1040. std::list<Client*> new_clients;
  1041. {
  1042. char * client_name = NULL;
  1043. char * client_executable = NULL;
  1044. char * client_id = NULL;
  1045. // load the client list
  1046. while ( fscanf( fp, "%m[^:]:%m[^:]:%m[^:\n]\n", &client_name, &client_executable, &client_id ) > 0 )
  1047. {
  1048. Client *c = new Client();
  1049. c->name = client_name;
  1050. c->executable_path = client_executable;
  1051. c->client_id = client_id;
  1052. asprintf( &c->name_with_id, "%s.%s", c->name, c->client_id );
  1053. new_clients.push_back( c );
  1054. }
  1055. }
  1056. fclose(fp);
  1057. MESSAGE( "Commanding unneeded and dumb clients to quit" );
  1058. std::map<std::string,int> client_map;
  1059. /* count how many instances of each client are needed in the new session */
  1060. for ( std::list<Client*>::iterator i = new_clients.begin();
  1061. i != new_clients.end();
  1062. ++i )
  1063. {
  1064. if ( client_map.find( (*i)->name) != client_map.end() )
  1065. client_map[(*i)->name]++;
  1066. else
  1067. client_map[(*i)->name] = 1;
  1068. }
  1069. for ( std::list<Client*>::iterator i = client.begin();
  1070. i != client.end();
  1071. ++i )
  1072. {
  1073. if ( ! (*i)->is_capable_of( ":switch:" ) || client_map.find((*i)->name ) == client_map.end() )
  1074. {
  1075. /* client is not capable of switch, or is not wanted in the new session */
  1076. command_client_to_quit( *i );
  1077. }
  1078. else
  1079. {
  1080. /* client is switch capable and may be wanted in the new session */
  1081. if ( client_map[ (*i)->name ]-- <= 0 )
  1082. /* nope,, we already have as many as we need, stop this one */
  1083. command_client_to_quit( *i );
  1084. }
  1085. }
  1086. // wait_for_replies();
  1087. wait_for_killed_clients_to_die();
  1088. // wait_for_dumb_clients_to_die();
  1089. purge_inactive_clients();
  1090. for ( std::list<Client*>::iterator i = client.begin();
  1091. i != client.end();
  1092. ++i )
  1093. {
  1094. (*i)->pre_existing = true;
  1095. }
  1096. MESSAGE( "Commanding smart clients to switch" );
  1097. for ( std::list<Client*>::iterator i = new_clients.begin();
  1098. i != new_clients.end();
  1099. ++i )
  1100. {
  1101. Client *c = NULL;
  1102. /* in a duplicated session, clients will have the same
  1103. * IDs, so be sure to pick the right one to avoid race
  1104. * conditions in JACK name registration. */
  1105. c = get_client_by_name_and_id( &client, (*i)->name, (*i)->client_id );
  1106. if ( ! c )
  1107. c = client_by_name( (*i)->name, &client );
  1108. if ( c && c->pre_existing && !c->reply_pending() )
  1109. {
  1110. // since we already shutdown clients not capable of 'switch', we can assume that these are.
  1111. command_client_to_switch( c, (*i)->client_id );
  1112. }
  1113. else
  1114. {
  1115. /* sleep a little bit because liblo derives its sequence
  1116. * of port numbers from the system time (second
  1117. * resolution) and if too many clients start at once they
  1118. * won't be able to find a free port. */
  1119. usleep( 100 * 1000 );
  1120. launch( (*i)->executable_path, (*i)->client_id );
  1121. }
  1122. }
  1123. /* this part is a little tricky... the clients need some time to
  1124. * send their 'announce' messages before we can send them 'open'
  1125. * and know that a reply is pending and we should continue waiting
  1126. * until they finish. wait_for_replies() must check for OSC
  1127. * messages immediately, even if no replies seem to be pending
  1128. * yet. */
  1129. /* dumb clients will never send an 'announce message', so we need
  1130. * to give up waiting on them fairly soon. */
  1131. wait_for_announce();
  1132. wait_for_replies();
  1133. tell_all_clients_session_is_loaded();
  1134. MESSAGE( "Loaded." );
  1135. new_clients.clear();
  1136. if ( gui_is_active )
  1137. { //This is not the case when --load-session was used. GUI announce will come later.
  1138. //Send two parameters to signal that the session was loaded. First is the direct session name,
  1139. //second is the full filepath.
  1140. //See function announce_gui for a full description where /nsm/gui/session/name is also send from
  1141. osc_server->send( gui_addr, "/nsm/gui/session/name", session_name, session_path + strlen( session_root ));
  1142. }
  1143. return ERR_OK;
  1144. }
  1145. OSC_HANDLER( save )
  1146. {
  1147. lo_address sender_addr;
  1148. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1149. if ( pending_operation != COMMAND_NONE )
  1150. {
  1151. osc_server->send( sender_addr, "/error", path,
  1152. ERR_OPERATION_PENDING,
  1153. "An operation pending." );
  1154. return 0;
  1155. }
  1156. if ( ! session_path )
  1157. {
  1158. osc_server->send( sender_addr, "/error", path,
  1159. ERR_NO_SESSION_OPEN,
  1160. "No session to save.");
  1161. goto done;
  1162. }
  1163. command_all_clients_to_save();
  1164. MESSAGE( "Done." );
  1165. osc_server->send( sender_addr, "/reply", path, "Saved." );
  1166. done:
  1167. pending_operation = COMMAND_NONE;
  1168. return 0;
  1169. }
  1170. OSC_HANDLER( duplicate )
  1171. {
  1172. lo_address sender_addr;
  1173. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1174. if ( pending_operation != COMMAND_NONE )
  1175. {
  1176. osc_server->send( sender_addr, "/error", path,
  1177. ERR_OPERATION_PENDING,
  1178. "An operation pending." );
  1179. return 0;
  1180. }
  1181. pending_operation = COMMAND_DUPLICATE;
  1182. if ( ! session_path )
  1183. {
  1184. osc_server->send( sender_addr, "/error", path,
  1185. ERR_NO_SESSION_OPEN,
  1186. "No session to duplicate.");
  1187. goto done;
  1188. }
  1189. if ( ! path_is_valid( &argv[0]->s ) )
  1190. {
  1191. osc_server->send( sender_addr, "/error", path,
  1192. ERR_CREATE_FAILED,
  1193. "Invalid session name." );
  1194. goto done;
  1195. }
  1196. command_all_clients_to_save();
  1197. if ( clients_have_errors() )
  1198. {
  1199. osc_server->send( sender_addr, "/error", path,
  1200. ERR_GENERAL_ERROR,
  1201. "Some clients could not save" );
  1202. goto done;
  1203. }
  1204. // save_session_file();
  1205. char *spath;
  1206. asprintf( &spath, "%s/%s", session_root, &argv[0]->s );
  1207. mkpath( spath, false );
  1208. /* FIXME: code a recursive copy instead of calling the shell */
  1209. char *cmd;
  1210. asprintf( &cmd, "cp -R \"%s\" \"%s\"", session_path, spath);
  1211. system( cmd );
  1212. free( cmd );
  1213. osc_server->send( gui_addr, "/nsm/gui/session/session", &argv[0]->s );
  1214. MESSAGE( "Attempting to open %s", spath );
  1215. if ( !load_session_file( spath ) )
  1216. {
  1217. MESSAGE( "Loaded" );
  1218. osc_server->send( sender_addr, "/reply", path,
  1219. "Loaded." );
  1220. }
  1221. else
  1222. {
  1223. MESSAGE( "Failed" );
  1224. osc_server->send( sender_addr, "/error", path,
  1225. ERR_NO_SUCH_FILE,
  1226. "No such file." );
  1227. free(spath);
  1228. return -1;
  1229. }
  1230. free( spath );
  1231. MESSAGE( "Done" );
  1232. osc_server->send( sender_addr, "/reply", path, "Duplicated." );
  1233. done:
  1234. pending_operation = COMMAND_NONE;
  1235. return 0;
  1236. }
  1237. OSC_HANDLER( new )
  1238. {
  1239. lo_address sender_addr;
  1240. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1241. if ( pending_operation != COMMAND_NONE )
  1242. {
  1243. osc_server->send( sender_addr, "/error", path,
  1244. ERR_OPERATION_PENDING,
  1245. "An operation pending." );
  1246. return 0;
  1247. }
  1248. pending_operation = COMMAND_NEW;
  1249. if ( ! path_is_valid( &argv[0]->s ) )
  1250. {
  1251. osc_server->send( sender_addr, "/error", path,
  1252. ERR_CREATE_FAILED,
  1253. "Invalid session name." );
  1254. pending_operation = COMMAND_NONE;
  1255. return 0;
  1256. }
  1257. if ( session_path )
  1258. {
  1259. command_all_clients_to_save();
  1260. close_session();
  1261. }
  1262. GUIMSG( "Creating new session \"%s\"", &argv[0]->s );
  1263. char *spath;
  1264. asprintf( &spath, "%s/%s", session_root, &argv[0]->s );
  1265. if ( mkpath( spath, true ) )
  1266. {
  1267. osc_server->send( sender_addr, "/error", path,
  1268. ERR_CREATE_FAILED,
  1269. "Could not create the session directory" );
  1270. free(spath);
  1271. pending_operation = COMMAND_NONE;
  1272. return 0;
  1273. }
  1274. session_path = strdup( spath );
  1275. set_name( session_path );
  1276. osc_server->send( sender_addr, "/reply", path, "Created." );
  1277. if ( gui_is_active )
  1278. {
  1279. osc_server->send( gui_addr, "/nsm/gui/session/session", &argv[0]->s );
  1280. osc_server->send( gui_addr, "/nsm/gui/session/name", &argv[0]->s, &argv[0]->s );
  1281. }
  1282. save_session_file();
  1283. free( spath );
  1284. osc_server->send( sender_addr, "/reply", path, "Session created" );
  1285. pending_operation = COMMAND_NONE;
  1286. return 0;
  1287. }
  1288. static lo_address list_response_address;
  1289. int
  1290. list_file ( const char *fpath, const struct stat *sb, int tflag )
  1291. {
  1292. if ( tflag == FTW_F )
  1293. {
  1294. char *s;
  1295. s = strdup( fpath );
  1296. if ( ! strcmp( "session.nsm", basename( s ) ) )
  1297. {
  1298. free( s );
  1299. s = strdup( fpath );
  1300. s = dirname( s );
  1301. memmove( s, s + strlen( session_root ) + 1, (strlen( s ) - strlen( session_root )) + 1);
  1302. osc_server->send( list_response_address, "/reply", "/nsm/server/list", s );
  1303. free( s );
  1304. }
  1305. else
  1306. free( s );
  1307. }
  1308. return 0;
  1309. }
  1310. OSC_HANDLER( list )
  1311. {
  1312. GUIMSG( "Listing sessions" );
  1313. list_response_address = lo_message_get_source( msg );
  1314. ftw( session_root, list_file, 20 );
  1315. // osc_server->send( lo_message_get_source( msg ), path, ERR_OK, "Done." );
  1316. // As marker that all sessions were sent reply with an empty string, which is impossible to conflict with a session name
  1317. osc_server->send( list_response_address, "/reply", "/nsm/server/list", "" );
  1318. return 0;
  1319. }
  1320. OSC_HANDLER( open )
  1321. {
  1322. lo_address sender_addr;
  1323. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1324. GUIMSG( "Opening session %s", &argv[0]->s );
  1325. if ( pending_operation != COMMAND_NONE )
  1326. {
  1327. osc_server->send( sender_addr, "/error", path,
  1328. ERR_OPERATION_PENDING,
  1329. "An operation pending." );
  1330. return 0;
  1331. }
  1332. pending_operation = COMMAND_OPEN;
  1333. if ( session_path )
  1334. {
  1335. command_all_clients_to_save();
  1336. if ( clients_have_errors() )
  1337. {
  1338. osc_server->send( sender_addr, "/error", path,
  1339. ERR_GENERAL_ERROR,
  1340. "Some clients could not save" );
  1341. pending_operation = COMMAND_NONE;
  1342. return 0;
  1343. }
  1344. // save_session_file();
  1345. }
  1346. char *spath;
  1347. asprintf( &spath, "%s/%s", session_root, &argv[0]->s );
  1348. MESSAGE( "Attempting to open %s", spath );
  1349. int err = load_session_file( spath );
  1350. if ( ! err )
  1351. {
  1352. MESSAGE( "Loaded" );
  1353. osc_server->send( sender_addr, "/reply", path,
  1354. "Loaded." );
  1355. }
  1356. else
  1357. {
  1358. MESSAGE( "Failed" );
  1359. const char *m = NULL;
  1360. switch ( err )
  1361. {
  1362. case ERR_CREATE_FAILED:
  1363. m = "Could not create session file!";
  1364. break;
  1365. case ERR_SESSION_LOCKED:
  1366. m = "Session is locked by another process!";
  1367. break;
  1368. case ERR_NO_SUCH_FILE:
  1369. m = "The named session does not exist.";
  1370. break;
  1371. default:
  1372. m = "Unknown error";
  1373. }
  1374. osc_server->send( sender_addr, "/error", path,
  1375. err,
  1376. m );
  1377. }
  1378. free( spath );
  1379. MESSAGE( "Done" );
  1380. pending_operation = COMMAND_NONE;
  1381. return 0;
  1382. }
  1383. OSC_HANDLER( quit )
  1384. {
  1385. close_session();
  1386. exit(0);
  1387. return 0;
  1388. }
  1389. OSC_HANDLER( abort )
  1390. {
  1391. lo_address sender_addr;
  1392. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1393. if ( pending_operation != COMMAND_NONE )
  1394. {
  1395. osc_server->send( sender_addr, "/error", path,
  1396. ERR_OPERATION_PENDING,
  1397. "An operation pending." );
  1398. return 0;
  1399. }
  1400. pending_operation = COMMAND_CLOSE;
  1401. if ( ! session_path )
  1402. {
  1403. osc_server->send( sender_addr, "/error", path,
  1404. ERR_NO_SESSION_OPEN,
  1405. "No session to abort." );
  1406. goto done;
  1407. }
  1408. GUIMSG( "Commanding attached clients to quit." );
  1409. close_session();
  1410. osc_server->send( sender_addr, "/reply", path,
  1411. "Aborted." );
  1412. MESSAGE( "Done" );
  1413. done:
  1414. pending_operation = COMMAND_NONE;
  1415. return 0;
  1416. }
  1417. OSC_HANDLER( close )
  1418. {
  1419. lo_address sender_addr;
  1420. sender_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
  1421. if ( pending_operation != COMMAND_NONE )
  1422. {
  1423. osc_server->send( sender_addr, "/error", path,
  1424. ERR_OPERATION_PENDING,
  1425. "An operation pending." );
  1426. return 0;
  1427. }
  1428. pending_operation = COMMAND_CLOSE;
  1429. if ( ! session_path )
  1430. {
  1431. osc_server->send( sender_addr, "/error", path,
  1432. ERR_NO_SESSION_OPEN,
  1433. "No session to close." );
  1434. goto done;
  1435. }
  1436. command_all_clients_to_save();
  1437. GUIMSG( "Commanding attached clients to quit." );
  1438. close_session();
  1439. osc_server->send( sender_addr, "/reply", path, "Closed." );
  1440. MESSAGE( "Done" );
  1441. done:
  1442. pending_operation = COMMAND_NONE;
  1443. return 0;
  1444. }
  1445. OSC_HANDLER( broadcast )
  1446. {
  1447. const char *to_path = &argv[0]->s;
  1448. /* don't allow clients to broadcast NSM commands */
  1449. if ( ! strncmp( to_path, "/nsm/", strlen( "/nsm/" ) ) )
  1450. return 0;
  1451. std::list<OSC::OSC_Value> new_args;
  1452. for ( int i = 1; i < argc; ++i )
  1453. {
  1454. switch ( types[i] )
  1455. {
  1456. case 's':
  1457. new_args.push_back( OSC::OSC_String( &argv[i]->s ) );
  1458. break;
  1459. case 'i':
  1460. new_args.push_back( OSC::OSC_Int( argv[i]->i ) );
  1461. break;
  1462. case 'f':
  1463. new_args.push_back( OSC::OSC_Float( argv[i]->f ) );
  1464. break;
  1465. }
  1466. }
  1467. char *sender_url = lo_address_get_url( lo_message_get_source( msg ) );
  1468. for ( std::list<Client*>::iterator i = client.begin();
  1469. i != client.end();
  1470. ++i )
  1471. {
  1472. if ( ! (*i)->addr )
  1473. continue;
  1474. char *url = lo_address_get_url( (*i)->addr );
  1475. if ( strcmp( sender_url, url ) )
  1476. {
  1477. osc_server->send( (*i)->addr, to_path, new_args );
  1478. }
  1479. free( url );
  1480. }
  1481. /* also relay to attached GUI so that the broadcast can be
  1482. * propagated to another NSMD instance */
  1483. if ( gui_is_active )
  1484. {
  1485. char *u1 = lo_address_get_url( gui_addr );
  1486. if ( strcmp( u1, sender_url ) )
  1487. {
  1488. new_args.push_front( OSC::OSC_String( to_path ) );
  1489. osc_server->send( gui_addr, path, new_args );
  1490. }
  1491. free(u1);
  1492. }
  1493. free( sender_url );
  1494. return 0;
  1495. }
  1496. /*********************************/
  1497. /* Client Informational Messages */
  1498. /*********************************/
  1499. OSC_HANDLER( progress )
  1500. {
  1501. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1502. if ( c )
  1503. {
  1504. c->progress = argv[0]->f;
  1505. /* MESSAGE( "%s progress: %i%%", c->name, (int)(c->progress * 100.0f) ); */
  1506. if ( gui_is_active )
  1507. {
  1508. osc_server->send( gui_addr, "/nsm/gui/client/progress", c->client_id, (float)c->progress );
  1509. }
  1510. }
  1511. return 0;
  1512. }
  1513. OSC_HANDLER( is_dirty )
  1514. {
  1515. MESSAGE( "Client sends dirty" );
  1516. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1517. if ( ! c )
  1518. return 0;
  1519. c->dirty = 1;
  1520. if ( gui_is_active )
  1521. osc_server->send( gui_addr, "/nsm/gui/client/dirty", c->client_id, c->dirty );
  1522. return 0;
  1523. }
  1524. OSC_HANDLER( is_clean )
  1525. {
  1526. MESSAGE( "Client sends clean" );
  1527. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1528. if ( ! c )
  1529. return 0;
  1530. c->dirty = 0;
  1531. if ( gui_is_active )
  1532. osc_server->send( gui_addr, "/nsm/gui/client/dirty", c->client_id, c->dirty );
  1533. return 0;
  1534. }
  1535. OSC_HANDLER( gui_is_hidden )
  1536. {
  1537. MESSAGE( "Client sends gui hidden" );
  1538. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1539. if ( ! c )
  1540. return 0;
  1541. c->gui_visible( false );
  1542. if ( gui_is_active )
  1543. osc_server->send( gui_addr, "/nsm/gui/client/gui_visible", c->client_id, c->gui_visible() );
  1544. return 0;
  1545. }
  1546. OSC_HANDLER( gui_is_shown )
  1547. {
  1548. MESSAGE( "Client sends gui shown" );
  1549. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1550. if ( ! c )
  1551. return 0;
  1552. c->gui_visible( true );
  1553. if ( gui_is_active )
  1554. osc_server->send( gui_addr, "/nsm/gui/client/gui_visible", c->client_id, c->gui_visible() );
  1555. return 0;
  1556. }
  1557. OSC_HANDLER( message )
  1558. {
  1559. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1560. if ( ! c )
  1561. return 0;
  1562. if ( gui_is_active )
  1563. osc_server->send( gui_addr, "/nsm/gui/client/message", c->client_id, argv[0]->i, &argv[1]->s );
  1564. return 0;
  1565. }
  1566. OSC_HANDLER( label )
  1567. {
  1568. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1569. if ( ! c )
  1570. return 0;
  1571. if ( strcmp( types, "s" ) )
  1572. return -1;
  1573. c->label( &argv[0]->s );
  1574. if ( gui_is_active )
  1575. osc_server->send( gui_addr, "/nsm/gui/client/label", c->client_id, &argv[0]->s );
  1576. return 0;
  1577. }
  1578. /**********************/
  1579. /* Response Handlers */
  1580. /**********************/
  1581. OSC_HANDLER( error )
  1582. {
  1583. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1584. if ( ! c )
  1585. {
  1586. WARNING( "Error from unknown client" );
  1587. return 0;
  1588. }
  1589. // const char *rpath = &argv[0]->s;
  1590. int err_code = argv[1]->i;
  1591. const char *message = &argv[2]->s;
  1592. c->set_reply( err_code, message );
  1593. MESSAGE( "Client \"%s\" replied with error: %s (%i) in %fms", c->name_with_id, message, err_code, c->milliseconds_since_last_command() );
  1594. c->pending_command( COMMAND_NONE );
  1595. c->status = "error";
  1596. if ( gui_is_active )
  1597. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  1598. return 0;
  1599. }
  1600. OSC_HANDLER( reply )
  1601. {
  1602. Client *c = get_client_by_address( lo_message_get_source( msg ) );
  1603. // const char *rpath = &argv[0]->s;
  1604. const char *message = &argv[1]->s;
  1605. if ( c )
  1606. {
  1607. c->set_reply( ERR_OK, message );
  1608. MESSAGE( "Client \"%s\" replied with: %s in %fms", c->name_with_id, message, c->milliseconds_since_last_command() );
  1609. c->pending_command( COMMAND_NONE );
  1610. c->status = "ready";
  1611. if ( gui_is_active )
  1612. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  1613. }
  1614. else
  1615. MESSAGE( "Reply from unknown client" );
  1616. return 0;
  1617. }
  1618. /******************/
  1619. /* GUI operations */
  1620. /******************/
  1621. OSC_HANDLER( stop )
  1622. {
  1623. Client *c = get_client_by_id( &client, &argv[0]->s );
  1624. if ( c )
  1625. {
  1626. command_client_to_stop( c );
  1627. if ( gui_is_active )
  1628. osc_server->send( gui_addr, "/reply", "Client stopped." );
  1629. }
  1630. else
  1631. {
  1632. if ( gui_is_active )
  1633. osc_server->send( gui_addr, "/error", -10, "No such client." );
  1634. }
  1635. return 0;
  1636. }
  1637. OSC_HANDLER( remove )
  1638. {
  1639. Client *c = get_client_by_id( &client, &argv[0]->s );
  1640. if ( c )
  1641. {
  1642. if ( c->pid == 0 &&
  1643. ! c->active )
  1644. {
  1645. c->status = "removed";
  1646. if ( gui_is_active )
  1647. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  1648. client.remove( c );
  1649. delete c;
  1650. if ( gui_is_active )
  1651. osc_server->send( gui_addr, "/reply", "Client removed." );
  1652. }
  1653. }
  1654. else
  1655. {
  1656. if ( gui_is_active )
  1657. osc_server->send( gui_addr, "/error", -10, "No such client." );
  1658. }
  1659. return 0;
  1660. }
  1661. OSC_HANDLER( resume )
  1662. {
  1663. Client *c = get_client_by_id( &client, &argv[0]->s );
  1664. /* FIXME: return error if no such client? */
  1665. if ( c )
  1666. {
  1667. if ( c->pid == 0 &&
  1668. ! c->active )
  1669. {
  1670. if ( ! launch( c->executable_path, c->client_id ) )
  1671. {
  1672. }
  1673. }
  1674. }
  1675. return 0;
  1676. }
  1677. OSC_HANDLER( client_save )
  1678. {
  1679. Client *c = get_client_by_id( &client, &argv[0]->s );
  1680. /* FIXME: return error if no such client? */
  1681. if ( c )
  1682. {
  1683. if ( c->active )
  1684. {
  1685. command_client_to_save( c );
  1686. }
  1687. }
  1688. return 0;
  1689. }
  1690. OSC_HANDLER( client_show_optional_gui )
  1691. {
  1692. Client *c = get_client_by_id( &client, &argv[0]->s );
  1693. /* FIXME: return error if no such client? */
  1694. if ( c )
  1695. {
  1696. if ( c->active )
  1697. {
  1698. osc_server->send( c->addr, "/nsm/client/show_optional_gui" );
  1699. }
  1700. }
  1701. return 0;
  1702. }
  1703. OSC_HANDLER( client_hide_optional_gui )
  1704. {
  1705. Client *c = get_client_by_id( &client, &argv[0]->s );
  1706. /* FIXME: return error if no such client? */
  1707. if ( c )
  1708. {
  1709. if ( c->active )
  1710. {
  1711. osc_server->send( c->addr, "/nsm/client/hide_optional_gui" );
  1712. }
  1713. }
  1714. return 0;
  1715. }
  1716. void
  1717. announce_gui( const char *url, bool is_reply )
  1718. {
  1719. // This is send for a new and empty nsmd as well as already running, headless, ones.
  1720. // If a GUI connects to an existing server with a running session this will trigger a list of
  1721. // clients send to the new GUI.
  1722. MESSAGE ( "A GUI announced to us from the URL %s", url );
  1723. gui_addr = lo_address_new_from_url( url );
  1724. gui_is_active = true; //global state
  1725. if ( is_reply )
  1726. // the default case. A GUI starts its own nsmd or connects to a running one
  1727. osc_server->send( gui_addr, "/nsm/gui/gui_announce", "hi" );
  1728. else
  1729. //The server was started directly and instructed to connect to a running GUI.
  1730. osc_server->send( gui_addr, "/nsm/gui/server_announce", "hi" );
  1731. osc_server->send( gui_addr, "/nsm/gui/session/root", session_root );
  1732. // Send a list of clients to the newly registered GUI in case there was already a session open
  1733. DMESSAGE ( "Informing GUI about %li already running clients", client.size() );
  1734. for ( std::list<Client*>::iterator i = client.begin();
  1735. i != client.end();
  1736. ++i )
  1737. {
  1738. Client *c = *i;
  1739. osc_server->send( gui_addr, "/nsm/gui/client/new", c->client_id, c->name );
  1740. osc_server->send( gui_addr, "/nsm/gui/client/status", c->client_id, c->status );
  1741. }
  1742. //Send two parameters. The first one is the short session name, which is the directory name.
  1743. //The second parameter is the full file path.
  1744. //If both are empty it signals that no session is currently open, which is the default state if
  1745. //a GUI started nsmd.
  1746. DMESSAGE( "Informing GUI about potentially running session name: %s", session_name );
  1747. osc_server->send( gui_addr, "/nsm/gui/session/name", session_name ? session_name : "", session_path ? session_path : "" );
  1748. DMESSAGE( "Registration with GUI complete" );
  1749. }
  1750. OSC_HANDLER( gui_announce )
  1751. {
  1752. announce_gui( lo_address_get_url( lo_message_get_source( msg ) ), true );
  1753. return 0;
  1754. }
  1755. OSC_HANDLER( ping )
  1756. {
  1757. osc_server->send( lo_message_get_source( msg ), "/reply", path );
  1758. return 0;
  1759. }
  1760. OSC_HANDLER( null )
  1761. {
  1762. WARNING( "Unrecognized message with type signature \"%s\" at path \"%s\"", types, path );
  1763. return 0;
  1764. }
  1765. static void
  1766. wait ( long timeout )
  1767. {
  1768. struct signalfd_siginfo fdsi;
  1769. ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo));
  1770. if (s == sizeof(struct signalfd_siginfo))
  1771. {
  1772. if (fdsi.ssi_signo == SIGCHLD)
  1773. handle_sigchld();
  1774. }
  1775. osc_server->wait( timeout );
  1776. purge_dead_clients();
  1777. }
  1778. int main(int argc, char *argv[])
  1779. {
  1780. sigset_t mask;
  1781. sigemptyset( &mask );
  1782. sigaddset( &mask, SIGCHLD );
  1783. sigprocmask(SIG_BLOCK, &mask, NULL );
  1784. signal_fd = signalfd( -1, &mask, SFD_NONBLOCK );
  1785. /* generate random seed for client ids */
  1786. {
  1787. time_t seconds;
  1788. time(&seconds);
  1789. srand( (unsigned int) seconds );
  1790. }
  1791. //Command line parameters
  1792. char *osc_port = NULL;
  1793. const char *gui_url = NULL;
  1794. const char *load_session = NULL;
  1795. static struct option long_options[] =
  1796. {
  1797. { "detach", no_argument, 0, 'd' },
  1798. { "session-root", required_argument, 0, 's' },
  1799. { "osc-port", required_argument, 0, 'p' },
  1800. { "gui-url", required_argument, 0, 'g' },
  1801. { "help", no_argument, 0, 'h' },
  1802. { "version", no_argument, 0, 'v' },
  1803. { "load-session", required_argument, 0, 'l'},
  1804. { 0, 0, 0, 0 }
  1805. };
  1806. int option_index = 0;
  1807. int c = 0;
  1808. bool detach = false;
  1809. while ( ( c = getopt_long_only( argc, argv, "", long_options, &option_index ) ) != -1 )
  1810. {
  1811. switch ( c )
  1812. {
  1813. case 'd':
  1814. detach = true;
  1815. break;
  1816. case 's':
  1817. {
  1818. session_root = optarg;
  1819. /* get rid of trailing slash */
  1820. char *s = rindex(session_root,'/');
  1821. if ( s == &session_root[strlen(session_root) - 1] )
  1822. *s = '\0';
  1823. break;
  1824. }
  1825. case 'p':
  1826. DMESSAGE( "Using OSC port %s", optarg );
  1827. osc_port = optarg;
  1828. break;
  1829. case 'g':
  1830. DMESSAGE( "Going to connect to GUI at: %s", optarg );
  1831. gui_url = optarg;
  1832. break;
  1833. case 'l':
  1834. DMESSAGE( "Loading existing session file %s", optarg);
  1835. load_session = optarg;
  1836. break;
  1837. case 'v':
  1838. printf( "%s 1.4\n", argv[0] );
  1839. exit(0);
  1840. break;
  1841. case 'h':
  1842. //Print usage message according to POSIX.1-2017
  1843. const char *usage =
  1844. "%s\n\n"
  1845. "Usage:\n"
  1846. " %s\n"
  1847. " %s --help\n"
  1848. " %s --version\n"
  1849. "\n"
  1850. "Options:\n"
  1851. " --help Show this screen\n"
  1852. " --version Show version\n"
  1853. " --osc-port portnum OSC port number [Default: provided by system].\n"
  1854. " --session-root path Base path for sessions [Default: ~/NSM Sessions].\n"
  1855. " --load-session name Load existing session [Example: \"My Song\"].\n"
  1856. " --gui-url url Connect to running legacy-gui [Example: osc.udp://mycomputer.localdomain:38356/].\n"
  1857. " --detach Detach from console.\n"
  1858. "";
  1859. printf ( usage, argv[0], argv[0], argv[0], argv[0] );
  1860. exit(0);
  1861. break;
  1862. }
  1863. }
  1864. if ( !session_root )
  1865. asprintf( &session_root, "%s/%s", getenv( "HOME" ), "NSM Sessions" );
  1866. struct stat st;
  1867. if ( stat( session_root, &st ) )
  1868. {
  1869. if ( mkdir( session_root, 0771 ) )
  1870. {
  1871. FATAL( "Failed to create session directory: %s", strerror( errno ) );
  1872. }
  1873. }
  1874. MESSAGE( "Session root is: %s", session_root );
  1875. osc_server = new OSC::Endpoint();
  1876. if ( osc_server->init( LO_UDP, osc_port ) )
  1877. {
  1878. FATAL( "Failed to create OSC server." );
  1879. }
  1880. printf( "NSM_URL=%s\n", osc_server->url() );
  1881. if ( gui_url )
  1882. {
  1883. //The server was started directly and instructed to connect to a running GUI.
  1884. announce_gui( gui_url, false );
  1885. }
  1886. /* */
  1887. osc_server->add_method( "/nsm/server/announce", "sssiii", OSC_NAME( announce ), NULL, "client_name,capabilities,executable,api_version_major,api_version_minor,client_pid" );
  1888. /* response handlers */
  1889. osc_server->add_method( "/reply", "ss", OSC_NAME( reply ), NULL, "err_code,msg" );
  1890. osc_server->add_method( "/error", "sis", OSC_NAME( error ), NULL, "err_code,msg" );
  1891. osc_server->add_method( "/nsm/client/progress", "f", OSC_NAME( progress ), NULL, "progress" );
  1892. osc_server->add_method( "/nsm/client/is_dirty", "", OSC_NAME( is_dirty ), NULL, "dirtiness" );
  1893. osc_server->add_method( "/nsm/client/is_clean", "", OSC_NAME( is_clean ), NULL, "dirtiness" );
  1894. osc_server->add_method( "/nsm/client/message", "is", OSC_NAME( message ), NULL, "message" );
  1895. osc_server->add_method( "/nsm/client/gui_is_hidden", "", OSC_NAME( gui_is_hidden ), NULL, "message" );
  1896. osc_server->add_method( "/nsm/client/gui_is_shown", "", OSC_NAME( gui_is_shown ), NULL, "message" );
  1897. osc_server->add_method( "/nsm/client/label", "s", OSC_NAME( label ), NULL, "message" );
  1898. /* */
  1899. osc_server->add_method( "/nsm/gui/gui_announce", "", OSC_NAME( gui_announce ), NULL, "" );
  1900. osc_server->add_method( "/nsm/gui/client/stop", "s", OSC_NAME( stop ), NULL, "client_id" );
  1901. osc_server->add_method( "/nsm/gui/client/remove", "s", OSC_NAME( remove ), NULL, "client_id" );
  1902. osc_server->add_method( "/nsm/gui/client/resume", "s", OSC_NAME( resume ), NULL, "client_id" );
  1903. osc_server->add_method( "/nsm/gui/client/save", "s", OSC_NAME( client_save ), NULL, "client_id" );
  1904. osc_server->add_method( "/nsm/gui/client/show_optional_gui", "s", OSC_NAME( client_show_optional_gui ), NULL, "client_id" );
  1905. osc_server->add_method( "/nsm/gui/client/hide_optional_gui", "s", OSC_NAME( client_hide_optional_gui ), NULL, "client_id" );
  1906. osc_server->add_method( "/osc/ping", "", OSC_NAME( ping ), NULL, "" );
  1907. osc_server->add_method( "/nsm/server/broadcast", NULL, OSC_NAME( broadcast ), NULL, "" );
  1908. osc_server->add_method( "/nsm/server/duplicate", "s", OSC_NAME( duplicate ), NULL, "" );
  1909. osc_server->add_method( "/nsm/server/abort", "", OSC_NAME( abort ), NULL, "" );
  1910. osc_server->add_method( "/nsm/server/list", "", OSC_NAME( list ), NULL, "" );
  1911. osc_server->add_method( "/nsm/server/add", "s", OSC_NAME( add ), NULL, "executable_name" );
  1912. osc_server->add_method( "/nsm/server/new", "s", OSC_NAME( new ), NULL, "name" );
  1913. osc_server->add_method( "/nsm/server/save", "", OSC_NAME( save ), NULL, "" );
  1914. osc_server->add_method( "/nsm/server/open", "s", OSC_NAME( open ), NULL, "name" );
  1915. osc_server->add_method( "/nsm/server/close", "", OSC_NAME( close ), NULL, "" );
  1916. osc_server->add_method( "/nsm/server/quit", "", OSC_NAME( quit ), NULL, "" );
  1917. osc_server->add_method( NULL, NULL, OSC_NAME( null ),NULL, "" );
  1918. if ( load_session )
  1919. {
  1920. char *spath;
  1921. asprintf( &spath, "%s/%s", session_root, load_session); // Build the session path. --load-session works with --session-root
  1922. MESSAGE( "LOAD SESSION %s", spath);
  1923. load_session_file( spath );
  1924. free ( spath );
  1925. }
  1926. if ( detach )
  1927. {
  1928. MESSAGE( "Detaching from console" );
  1929. if ( fork() )
  1930. {
  1931. exit( 0 );
  1932. }
  1933. else
  1934. {
  1935. fclose( stdin );
  1936. fclose( stdout );
  1937. fclose( stderr );
  1938. }
  1939. }
  1940. /* listen for sigchld signals and process OSC messages forever */
  1941. for ( ;; )
  1942. {
  1943. wait( 1000 );
  1944. }
  1945. // osc_server->run();
  1946. return 0;
  1947. }