Jack2 1.9.10

JackPosixServerLaunch.cpp

00001 /*
00002 Copyright (C) 2001-2003 Paul Davis
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU Lesser General Public License as published by
00007 the Free Software Foundation; either version 2.1 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 
00019 */
00020 #if !defined(WIN32) || defined(__CYGWIN__)
00021 
00022 #ifdef PTHREAD_WIN32        // Added by JE - 13-02-2010
00023 #include <ptw32/pthread.h>  // Makes sure we #include the ptw32 version for
00024 #endif                      // consistency - even though we won't need it !
00025 
00026 #include "JackConstants.h"
00027 #include "JackChannel.h"
00028 #include "JackLibGlobals.h"
00029 #include "JackServerLaunch.h"
00030 #include "JackPlatformPlug.h"
00031 
00032 #include <sys/wait.h>
00033 
00034 using namespace Jack;
00035 
00036 #if defined(USE_LIBDBUS_AUTOLAUNCH)
00037 
00038 #include <dbus/dbus.h>
00039 
00040 static int start_server_dbus(const char* server_name)
00041 {
00042     DBusError err;
00043     DBusConnection *conn;
00044     DBusMessage *msg;
00045 
00046     // initialise the errors
00047     dbus_error_init(&err);
00048 
00049     // connect to the bus
00050     conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
00051     if (dbus_error_is_set(&err)) {
00052         fprintf(stderr, "Connection Error (%s)\n", err.message);
00053         dbus_error_free(&err);
00054     }
00055     if (NULL == conn) {
00056         return 1;
00057     }
00058 
00059     msg = dbus_message_new_method_call(
00060         "org.jackaudio.service",     // target for the method call
00061         "/org/jackaudio/Controller", // object to call on
00062         "org.jackaudio.JackControl", // interface to call on
00063         "StartServer");              // method name
00064     if (NULL == msg) {
00065         fprintf(stderr, "Message Null\n");
00066         return 1;
00067     }
00068 
00069     // send message and get a handle for a reply
00070     if (!dbus_connection_send(conn, msg, NULL))
00071     {
00072         fprintf(stderr, "Out Of Memory!\n");
00073         return 1;
00074     }
00075 
00076     dbus_message_unref(msg);
00077     dbus_connection_flush(conn);
00078     dbus_error_free(&err);
00079 
00080     return 0;
00081 }
00082 
00083 #elif defined(USE_CLASSIC_AUTOLAUNCH)
00084 
00085 /* Exec the JACK server in this process.  Does not return. */
00086 static void start_server_classic_aux(const char* server_name)
00087 {
00088     FILE* fp = 0;
00089     char filename[255];
00090     char arguments[255];
00091     char buffer[255];
00092     char* command = 0;
00093     size_t pos = 0;
00094     size_t result = 0;
00095     char** argv = 0;
00096     int i = 0;
00097     int good = 0;
00098     int res;
00099 
00100     snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
00101     fp = fopen(filename, "r");
00102 
00103     if (!fp) {
00104         fp = fopen("/etc/jackdrc", "r");
00105     }
00106     /* if still not found, check old config name for backwards compatability */
00107     if (!fp) {
00108         fp = fopen("/etc/jackd.conf", "r");
00109     }
00110 
00111     if (fp) {
00112         arguments[0] = '\0';
00113         res = fscanf(fp, "%s", buffer);
00114         while (res != 0 && res != EOF) {
00115             strcat(arguments, buffer);
00116             strcat(arguments, " ");
00117             res = fscanf(fp, "%s", buffer);
00118         }
00119         if (strlen(arguments) > 0) {
00120             good = 1;
00121         }
00122         fclose(fp);
00123     }
00124 
00125     if (!good) {
00126         command = (char*)(JACK_LOCATION "/jackd");
00127         strncpy(arguments, JACK_LOCATION "/jackd -T -d "JACK_DEFAULT_DRIVER, 255);
00128     } else {
00129         result = strcspn(arguments, " ");
00130         command = (char*)malloc(result + 1);
00131         strncpy(command, arguments, result);
00132         command[result] = '\0';
00133     }
00134 
00135     argv = (char**)malloc(255);
00136 
00137     while (1) {
00138         /* insert -T and -nserver_name in front of arguments */
00139         if (i == 1) {
00140             argv[i] = (char*)malloc(strlen ("-T") + 1);
00141             strcpy (argv[i++], "-T");
00142             if (server_name) {
00143                 size_t optlen = strlen("-n");
00144                 char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
00145                 strcpy(buf, "-n");
00146                 strcpy(buf + optlen, server_name);
00147                 argv[i++] = buf;
00148             }
00149         }
00150 
00151         result = strcspn(arguments + pos, " ");
00152         if (result == 0) {
00153             break;
00154         }
00155         argv[i] = (char*)malloc(result + 1);
00156         strncpy(argv[i], arguments + pos, result);
00157         argv[i][result] = '\0';
00158         pos += result + 1;
00159         ++i;
00160     }
00161     argv[i] = 0;
00162     execv(command, argv);
00163 
00164     /* If execv() succeeds, it does not return. There's no point
00165      * in calling jack_error() here in the child process. */
00166     fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
00167 }
00168 
00169 static int start_server_classic(const char* server_name)
00170 {
00171     /* The double fork() forces the server to become a child of
00172      * init, which will always clean up zombie process state on
00173      * termination. This even works in cases where the server
00174      * terminates but this client does not.
00175      *
00176      * Since fork() is usually implemented using copy-on-write
00177      * virtual memory tricks, the overhead of the second fork() is
00178      * probably relatively small.
00179      */
00180      
00181     int status;
00182     pid_t first_child_pid;
00183     
00184     first_child_pid = fork();
00185     switch (first_child_pid) {
00186         case 0:                                 /* child process */
00187             switch (fork()) {
00188                 case 0:                 /* grandchild process */
00189                     start_server_classic_aux(server_name);
00190                     _exit(99);  /* exec failed */
00191                 case - 1:
00192                     _exit(98);
00193                 default:
00194                     _exit(0);
00195             }
00196         case - 1:                       /* fork() error */
00197             return 1;           /* failed to start server */
00198     }
00199     waitpid(first_child_pid, &status, 0);
00200 
00201     /* only the original parent process goes here */
00202     return 0;                   /* (probably) successful */
00203 }
00204 
00205 #endif
00206 
00207 static int start_server(const char* server_name, jack_options_t options)
00208 {
00209     if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
00210         return 1;
00211     }
00212 
00213 #if defined(USE_LIBDBUS_AUTOLAUNCH)
00214     return start_server_dbus(server_name);
00215 #elif defined(USE_CLASSIC_AUTOLAUNCH)
00216     return start_server_classic(server_name);
00217 #else
00218     fprintf(stderr, "Automatic start of JACK server is disabled at configure time\n");
00219     return 1;
00220 #endif
00221 }
00222 
00223 static int server_connect(char* server_name)
00224 {
00225     JackClientChannel channel;
00226     int res = channel.ServerCheck(server_name);
00227     channel.Close();
00228     JackSleep(2000); // Added by JE - 02-01-2009 (gives
00229                      // the channel some time to close)
00230     return res;
00231 }
00232 
00233 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
00234 {
00235     if (server_connect(va->server_name) < 0) {
00236         int trys;
00237         if (start_server(va->server_name, options)) {
00238             int my_status1 = *status | JackFailure | JackServerFailed;
00239             *status = (jack_status_t)my_status1;
00240             return -1;
00241         }
00242         trys = 5;
00243         do {
00244             sleep(1);
00245             if (--trys < 0) {
00246                 int my_status1 = *status | JackFailure | JackServerFailed;
00247                 *status = (jack_status_t)my_status1;
00248                 return -1;
00249             }
00250         } while (server_connect(va->server_name) < 0);
00251         int my_status1 = *status | JackServerStarted;
00252         *status = (jack_status_t)my_status1;
00253     }
00254 
00255     return 0;
00256 }
00257 
00258 #endif  // !defined(WIN32) || defined(__CYGWIN__)