@@ -12,6 +12,7 @@ nsmd now follows the XDG Base Directory Specifications: | |||||
Lockfiles fixed (see issue #gh-31) | Lockfiles fixed (see issue #gh-31) | ||||
Lockfiles are now in $XDG_RUNTIME_DIR/nsm/ | Lockfiles are now in $XDG_RUNTIME_DIR/nsm/ | ||||
Lockfiles now each contain the session path, the osc NSM_URL and the nsmd PID | Lockfiles now each contain the session path, the osc NSM_URL and the nsmd PID | ||||
One daemon file for each currently running nsmd is created in $XDG_RUNTIME_DIR/nsm/d/ containing the osc url. This enables discovery of running daemons. | |||||
New section in the API documentation for the above. | New section in the API documentation for the above. | ||||
Fixes and guards against trying to load non-existing sessions and creating new sessions under existing names | Fixes and guards against trying to load non-existing sessions and creating new sessions under existing names | ||||
@@ -467,6 +467,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b | |||||
<ul class="sectlevel4"> | <ul class="sectlevel4"> | ||||
<li><a href="#_subdirectories_hierarchical_structure">1.2.3.1. Subdirectories / Hierarchical Structure</a></li> | <li><a href="#_subdirectories_hierarchical_structure">1.2.3.1. Subdirectories / Hierarchical Structure</a></li> | ||||
<li><a href="#_lockfiles">1.2.3.2. Lockfiles</a></li> | <li><a href="#_lockfiles">1.2.3.2. Lockfiles</a></li> | ||||
<li><a href="#_daemon_discovery">1.2.3.3. Daemon Discovery</a></li> | |||||
</ul> | </ul> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
@@ -796,6 +797,19 @@ osc.udp://myuser.localdomain:11287/ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="sect4"> | |||||
<h5 id="_daemon_discovery">1.2.3.3. Daemon Discovery</h5> | |||||
<div class="paragraph"> | |||||
<p>Each running <code>nsmd</code>, per user, creates a state file under <code>$XDG_RUNTIME_DIR/nsm/d/</code> (usually | |||||
<code>/run/user/XXXX/nsm/d/</code>) that can be used to look up running daemons, even if no session is loaded. | |||||
The files contains the daemons osc.udp URL that is compatible with the --nsm-url parameter of the GUI.</p> | |||||
</div> | |||||
<div class="paragraph"> | |||||
<p>This enables you to e.g. start nsmd at boot with a random free port. Server-control programs such | |||||
as GUIs can then use this to look for running servers without requiring the user to look up and | |||||
input an osc URL manually as command line parameter.</p> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -1871,7 +1885,7 @@ behaviour more strictly as well, removing false session entries in 3rd party cli | |||||
<li> | <li> | ||||
<p>nsmd now follows the XDG Base Directory Specifications for it’s session root and lock files. This | <p>nsmd now follows the XDG Base Directory Specifications for it’s session root and lock files. This | ||||
if of no consequence to clients but required documentation nevertheless, which was described as | if of no consequence to clients but required documentation nevertheless, which was described as | ||||
"background information" in the new section.</p> | |||||
"background information" in the chapters for lock files and daemon disovery.</p> | |||||
</li> | </li> | ||||
</ul> | </ul> | ||||
</div> | </div> | ||||
@@ -1882,7 +1896,7 @@ if of no consequence to clients but required documentation nevertheless, which w | |||||
<div id="footer"> | <div id="footer"> | ||||
<div id="footer-text"> | <div id="footer-text"> | ||||
Version API 1.1.2<br> | Version API 1.1.2<br> | ||||
Last updated 2022-03-05 12:34:04 +0100 | |||||
Last updated 2022-03-15 18:44:44 +0100 | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</body> | </body> |
@@ -557,7 +557,7 @@ Documentation and tutorials for software-developers will be added at a later dat | |||||
<div id="footer"> | <div id="footer"> | ||||
<div id="footer-text"> | <div id="footer-text"> | ||||
Version 1.6.0<br> | Version 1.6.0<br> | ||||
Last updated 2022-03-05 12:34:04 +0100 | |||||
Last updated 2022-03-15 18:44:44 +0100 | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</body> | </body> |
@@ -230,6 +230,18 @@ osc.udp://myuser.localdomain:11287/ | |||||
3022 | 3022 | ||||
``` | ``` | ||||
===== Daemon Discovery | |||||
Each running `nsmd`, per user, creates a state file under `$XDG_RUNTIME_DIR/nsm/d/` (usually | |||||
`/run/user/XXXX/nsm/d/`) that can be used to look up running daemons, even if no session is loaded. | |||||
The files contains the daemons osc.udp URL that is compatible with the --nsm-url parameter of the GUI. | |||||
This enables you to e.g. start nsmd at boot with a random free port. Server-control programs such | |||||
as GUIs can then use this to look for running servers without requiring the user to look up and | |||||
input an osc URL manually as command line parameter. | |||||
== NSM OSC Protocol | == NSM OSC Protocol | ||||
All message parameters are REQUIRED. All messages MUST be sent from the same socket as the `announce` | All message parameters are REQUIRED. All messages MUST be sent from the same socket as the `announce` | ||||
@@ -908,4 +920,4 @@ behaviour more strictly as well, removing false session entries in 3rd party cli | |||||
* nsmd now follows the XDG Base Directory Specifications for it's session root and lock files. This | * nsmd now follows the XDG Base Directory Specifications for it's session root and lock files. This | ||||
if of no consequence to clients but required documentation nevertheless, which was described as | if of no consequence to clients but required documentation nevertheless, which was described as | ||||
"background information" in the new section. | |||||
"background information" in the chapters for lock files and daemon disovery. |
@@ -64,6 +64,7 @@ static int signal_fd; | |||||
static char *session_root; | static char *session_root; | ||||
static char *lockfile_directory; | static char *lockfile_directory; | ||||
static char *daemon_file; | |||||
#define NSM_API_VERSION_MAJOR 1 | #define NSM_API_VERSION_MAJOR 1 | ||||
#define NSM_API_VERSION_MINOR 1 | #define NSM_API_VERSION_MINOR 1 | ||||
@@ -2584,6 +2585,10 @@ handle_signal_clean_exit ( int signal ) | |||||
close_session(); | close_session(); | ||||
free( session_root ); | free( session_root ); | ||||
free( lockfile_directory ); | free( lockfile_directory ); | ||||
unlink( daemon_file ); | |||||
MESSAGE( "Deleted daemon file %s", daemon_file ); | |||||
free( daemon_file ); | |||||
exit(0); | exit(0); | ||||
} | } | ||||
@@ -2717,9 +2722,24 @@ int main(int argc, char *argv[]) | |||||
} | } | ||||
} | } | ||||
MESSAGE( "Using %s for lock-files.", lockfile_directory ); | MESSAGE( "Using %s for lock-files.", lockfile_directory ); | ||||
} | |||||
//Now create another subdir for daemons .../nsm/d/ where each daemon has a port number file | |||||
char * daemon_directory; | |||||
asprintf( &daemon_directory, "%s/d", lockfile_directory); | |||||
struct stat st_daemonfile_dir_mkdir; | |||||
if ( stat( daemon_directory, &st_daemonfile_dir_mkdir ) ) | |||||
{ | |||||
if ( mkdir( daemon_directory, 0771 ) ) | |||||
{ | |||||
FATAL( "Failed to create daemon file directory %s with error: %s", daemon_directory, strerror( errno ) ); | |||||
} | |||||
} | |||||
//daemon_file is a global var | |||||
asprintf( &daemon_file, "%s/%d", daemon_directory, getpid()); | |||||
free ( daemon_directory ); | |||||
MESSAGE( "Using %s as daemon file.", daemon_file ); | |||||
//The actual daemon file will be written below after announcing the session url. | |||||
} | |||||
if ( !session_root ) { | if ( !session_root ) { | ||||
/* The user gave no specific session directory. We use the default. | /* The user gave no specific session directory. We use the default. | ||||
@@ -2736,6 +2756,7 @@ int main(int argc, char *argv[]) | |||||
*/ | */ | ||||
struct stat st_session_root; | struct stat st_session_root; | ||||
//TODO: Valgrind shows a memory leak for the next line. Why? | |||||
asprintf( &session_root, "%s/%s", getenv( "HOME" ), "NSM Sessions" ); | asprintf( &session_root, "%s/%s", getenv( "HOME" ), "NSM Sessions" ); | ||||
if ( stat( session_root, &st_session_root ) == 0 && S_ISDIR(st_session_root.st_mode)) { | if ( stat( session_root, &st_session_root ) == 0 && S_ISDIR(st_session_root.st_mode)) { | ||||
WARNING ( "An old session directory was detected in %s. You can continue to use it but it is recommended to move your sessions to $XDG_DATA_HOME/nsm-sessions/. If you don't know where that is simply rename your current session-directory and start nsmd, which will tell you the new directory.", session_root); | WARNING ( "An old session directory was detected in %s. You can continue to use it but it is recommended to move your sessions to $XDG_DATA_HOME/nsm-sessions/. If you don't know where that is simply rename your current session-directory and start nsmd, which will tell you the new directory.", session_root); | ||||
@@ -2775,7 +2796,20 @@ int main(int argc, char *argv[]) | |||||
FATAL( "Failed to create OSC server." ); | FATAL( "Failed to create OSC server." ); | ||||
} | } | ||||
printf( "NSM_URL=%s\n", osc_server->url() ); | |||||
char * url = osc_server->url(); | |||||
printf( "NSM_URL=%s\n", url ); | |||||
//Write the URL into the daemon_file that is named after our PID | |||||
FILE *fpdaemon = fopen( daemon_file, "w" ); | |||||
if ( !fpdaemon ) { | |||||
FATAL( "Failed to write daemon file to %s with error: %s", daemon_file, strerror( errno ) ); | |||||
} | |||||
fprintf( fpdaemon, "%s\n", url ); | |||||
MESSAGE( "Created daemon file %s", daemon_file ); | |||||
fclose( fpdaemon ); | |||||
free( url ); | |||||
if ( gui_url ) | if ( gui_url ) | ||||
{ | { | ||||
@@ -2847,24 +2881,20 @@ int main(int argc, char *argv[]) | |||||
} | } | ||||
/* listen for sigchld signals and process OSC messages forever */ | /* listen for sigchld signals and process OSC messages forever */ | ||||
int start_pid = getppid(); //get parent pid | |||||
int start_ppid = getppid(); //get parent pid | |||||
for ( ;; ) | for ( ;; ) | ||||
{ | { | ||||
wait( 1000 ); //1000 ms | wait( 1000 ); //1000 ms | ||||
//This still has some corner cases, like a race condition on startup that never gets the real PID, but | //This still has some corner cases, like a race condition on startup that never gets the real PID, but | ||||
//we cover the majority of cases at least: | //we cover the majority of cases at least: | ||||
if ( start_pid != getppid() ) { | |||||
WARNING ( "Our parent PID changed from %d to %d, which indicates a possible GUI crash. The user has no control over the session anymore. Trying to shut down cleanly.", start_pid, getppid()); | |||||
if ( start_ppid != getppid() ) { | |||||
WARNING ( "Our parent PID changed from %d to %d, which indicates a possible GUI crash. The user has no control over the session anymore. Trying to shut down cleanly.", start_ppid, getppid()); | |||||
handle_signal_clean_exit ( 0 ); | handle_signal_clean_exit ( 0 ); | ||||
} | } | ||||
} | } | ||||
//Code after here will not be executed if nsmd is stopped with any abort-signal like SIGINT. | //Code after here will not be executed if nsmd is stopped with any abort-signal like SIGINT. | ||||
//Without a signal handler clients will remain active ("zombies") without nsmd as parent. | //Without a signal handler clients will remain active ("zombies") without nsmd as parent. | ||||
//MESSAGE ( "End of Program"); | |||||
//free(session_root);// This was not executed if nsmd received a stop signal. It is now handled by handle_signal_clean_exit() | |||||
//osc_server->run(); | |||||
//Therefore exit is handled by handle_signal_clean_exit() | |||||
return 0; | return 0; | ||||
} | } |