Jack2  1.9.10
JackWinServerLaunch.cpp
00001 /*
00002 Copyright (C) 2001-2003 Paul Davis
00003 Copyright (C) 2004-2008 Grame
00004 Copyright (C) 2011 John Emmas
00005 
00006 This program is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU Lesser General Public License as published by
00008 the Free Software Foundation; either version 2.1 of the License, or
00009 (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 
00020 */
00021 
00022 #include "JackChannel.h"
00023 #include "JackLibGlobals.h"
00024 #include "JackServerLaunch.h"
00025 #include "JackPlatformPlug.h"
00026 
00027 using namespace Jack;
00028 
00029 #include <shlobj.h>
00030 #include <process.h>
00031 #include <string.h>
00032 #include <fcntl.h>
00033 #include <io.h>
00034 
00035 #if defined(_MSC_VER) || defined(__MINGW__) || defined(__MINGW32__)
00036 
00037 static char*
00038 find_path_to_jackdrc(char *path_to_jackdrc)
00039 {
00040     char user_jackdrc[1024];
00041     char *ret = NULL;
00042 
00043         user_jackdrc[0] = user_jackdrc[1] = 0; // Initialise
00044 
00045         if (S_OK == SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, user_jackdrc))
00046         {
00047                 // The above call should have given us the path to the user's home folder
00048                 char ch = user_jackdrc[strlen(user_jackdrc)-1];
00049 
00050                 if (('/' != ch) && ('\\' != ch))
00051                         strcat(user_jackdrc, "\\");
00052 
00053                 if (user_jackdrc[1] == ':')
00054                 {
00055                         // Assume we have a valid path
00056                         strcat(user_jackdrc, ".jackdrc");
00057                         strcpy(path_to_jackdrc, user_jackdrc);
00058 
00059                         ret = path_to_jackdrc;
00060                 }
00061                 else
00062                         path_to_jackdrc[0] = '\0';
00063         }
00064         else
00065                 path_to_jackdrc[0] = '\0';
00066 
00067         return (ret);
00068 }
00069 
00070 #else
00071 
00072 static char*
00073 find_path_to_jackdrc(char *path_to_jackdrc)
00074 {
00075         return 0;
00076 }
00077 
00078 #endif
00079 
00080 /* 'start_server_aux()' - this function might need to be modified (though probably
00081  * not) to cope with compilers other than MSVC (e.g. MinGW). The function
00082  * 'find_path_to_jackdrc()' might also need to be written for MinGW, though for
00083  * Cygwin, JackPosixServerLaunch.cpp can be used instead of this file.
00084  */
00085 
00086 #include <direct.h>
00087 
00088 static int start_server_aux(const char* server_name)
00089 {
00090     FILE*  fp      = 0;
00091     size_t pos     = 0;
00092     size_t result  = 0;
00093     int    i       = 0;
00094     int    good    = 0;
00095     int    ret     = 0;
00096     char*  command = 0;
00097     char** argv    = 0;
00098     char*  p;
00099     char*  back_slash;
00100     char*  forward_slash;
00101     char   arguments [256];
00102     char   buffer    [MAX_PATH];
00103     char   filename  [MAX_PATH];
00104     char   curr_wd   [MAX_PATH];
00105 
00106         curr_wd[0] = '\0';
00107         if (find_path_to_jackdrc(filename))
00108                 fp = fopen(filename, "r");
00109 
00110         /* if still not found, check old config name for backwards compatability */
00111         /* JE - hopefully won't be needed for the Windows build
00112     if (!fp) {
00113         fp = fopen("/etc/jackd.conf", "r");
00114     }
00115     */
00116 
00117         if (fp) {
00118                 arguments[0] = '\0';
00119 
00120                 fgets(filename, MAX_PATH, fp);
00121                 _strlwr(filename);
00122                 if ((p = strstr(filename, ".exe"))) {
00123                         p += 4;
00124                         *p = '\0';
00125                         pos = (size_t)(p - filename);
00126                         fseek(fp, 0, SEEK_SET);
00127 
00128                         if ((command = (char*)malloc(pos+1)))
00129                                 ret = fread(command, 1, pos, fp);
00130 
00131                         if (ret && !ferror(fp)) {
00132                                 command[pos]  = '\0'; // NULL terminator
00133                                 back_slash    = strrchr(command, '\\');
00134                                 forward_slash = strrchr(command, '/');
00135                                 if (back_slash > forward_slash)
00136                                         p = back_slash + 1;
00137                                 else
00138                                         p = forward_slash + 1;
00139 
00140                                 strcpy(buffer, p);
00141                                 while (ret != 0 && ret != EOF) {
00142                                         strcat(arguments, buffer);
00143                                         strcat(arguments, " ");
00144                                         ret = fscanf(fp, "%s", buffer);
00145                                 }
00146 
00147                                 if (strlen(arguments) > 0) {
00148                                         good = 1;
00149                                 }
00150                         }
00151                 }
00152 
00153                 fclose(fp);
00154         }
00155 
00156     if (!good) {
00157                 strcpy(buffer, JACK_LOCATION "/jackd.exe");
00158                 command = (char*)malloc((strlen(buffer))+1);
00159                 strcpy(command, buffer);
00160         strncpy(arguments, "jackd.exe -S -d " JACK_DEFAULT_DRIVER, 255);
00161     }
00162 
00163     int  buffer_termination;
00164     bool verbose_mode = false;
00165     argv = (char**)malloc(255);
00166     pos  = 0;
00167 
00168     while (1) {
00169         /* insert -T and -n server_name in front of arguments */
00170         if (i == 1) {
00171             argv[i] = (char*)malloc(strlen ("-T") + 1);
00172             strcpy (argv[i++], "-T");
00173             if (server_name) {
00174                 size_t optlen = strlen("-n");
00175                 char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
00176                 strcpy(buf, "-n");
00177                 strcpy(buf + optlen, server_name);
00178                 argv[i++] = buf;
00179             }
00180         }
00181 
00182                 // Only get the next character if there's more than 1 character
00183                 if ((pos < strlen(arguments)) && (arguments[pos+1]) && (arguments[pos+1] != ' ')) {
00184                         strncpy(buffer, arguments + pos++, 1);
00185                         buffer_termination = 1;
00186                 } else {
00187                         buffer[0] = '\0';
00188                         buffer_termination = 0;
00189                 }
00190 
00191                 buffer[1] = '\0';
00192                 if (buffer[0] == '\"')
00193                         result = strcspn(arguments + pos, "\"");
00194                 else
00195                         result = strcspn(arguments + pos, " ");
00196 
00197         if (0 == result)
00198             break;
00199                 else
00200                 {
00201                         strcat(buffer, arguments + pos);
00202 
00203                         // Terminate the buffer
00204                         buffer[result + buffer_termination] = '\0';
00205                         if (buffer[0] == '\"') {
00206                                 strcat(buffer, "\"");
00207                                 ++result;
00208                         }
00209 
00210                         argv[i] = (char*)malloc(strlen(buffer) + 1);
00211                         strcpy(argv[i], buffer);
00212                         pos += (result + 1);
00213                         ++i;
00214 
00215                         if ((0 == strcmp(buffer, "-v")) || (0 == strcmp(buffer, "--verbose")))
00216                                 verbose_mode = true;
00217                 }
00218     }
00219 
00220         argv[i] = 0;
00221 
00222 #ifdef SUPPORT_PRE_1_9_8_SERVER
00223         // Get the current working directory
00224         if (_getcwd(curr_wd, MAX_PATH)) {
00225                 strcpy(temp_wd, command);
00226                 back_slash    = strrchr(temp_wd, '\\');
00227                 forward_slash = strrchr(temp_wd, '/');
00228                 if (back_slash > forward_slash)
00229                         p = back_slash;
00230                 else
00231                         p = forward_slash;
00232                 *p = '\0';
00233 
00234                 // Accommodate older versions of Jack (pre v1.9.8) which
00235                 // might need to be started from their installation folder.
00236                 _chdir(temp_wd);
00237         }
00238 #endif
00239 
00240         if (verbose_mode) {
00241                 // Launch the server with a console... (note that
00242                 // if the client is a console app, the server might
00243                 // also use the client's console)
00244                 ret = _spawnv(_P_NOWAIT, command, argv);
00245         } else {
00246                 // Launch the server silently... (without a console)
00247                 ret = _spawnv(_P_DETACH, command, argv);
00248         }
00249 
00250     Sleep(2500); // Give it some time to launch
00251 
00252         if ((-1) == ret)
00253                 fprintf(stderr, "Execution of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
00254 
00255         if (strlen(curr_wd)) {
00256                 // Change the cwd back to its original setting
00257                 _chdir(curr_wd);
00258         }
00259 
00260         if (command)
00261                 free(command);
00262 
00263         if (argv) {
00264                 for (i = 0; argv[i] != 0; i++)
00265                         free (argv[i]);
00266 
00267                 free(argv);
00268         }
00269 
00270         return (ret == (-1) ? false : true);
00271 }
00272 
00273 static int start_server(const char* server_name, jack_options_t options)
00274 {
00275         if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
00276                 return 1;
00277         }
00278 
00279         return (((-1) != (start_server_aux(server_name)) ? 0 : (-1)));
00280 }
00281 
00282 static int server_connect(const char* server_name)
00283 {
00284         JackClientChannel channel;
00285         int res = channel.ServerCheck(server_name);
00286         channel.Close();
00287         /*
00288         JackSleep(2000); // Added by JE - 02-01-2009 (gives
00289                          // the channel some time to close)
00290                          */
00291     JackSleep(500);
00292         return res;
00293 }
00294 
00295 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
00296 {
00297         if (server_connect(va->server_name) < 0) {
00298                 int trys;
00299                 if (start_server(va->server_name, options)) {
00300                         int my_status1 = *status | JackFailure | JackServerFailed;
00301                         *status = (jack_status_t)my_status1;
00302                         return -1;
00303                 }
00304                 trys = 5;
00305                 do {
00306                         Sleep(1000);
00307                         if (--trys < 0) {
00308                                 int my_status1 = *status | JackFailure | JackServerFailed;
00309                                 *status = (jack_status_t)my_status1;
00310                                 return -1;
00311                         }
00312                 } while (server_connect(va->server_name) < 0);
00313                 int my_status1 = *status | JackServerStarted;
00314                 *status = (jack_status_t)my_status1;
00315         }
00316 
00317         return 0;
00318 }