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.

2399 lines
57KB

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