Jack2  1.9.8
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 *ptr = NULL;
00042     char *ret = NULL;
00043 
00044         user_jackdrc[0] = user_jackdrc[1] = 0; // Initialise
00045 
00046         if (S_OK == SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, user_jackdrc))
00047         {
00048                 // The above call should have given us the path to the user's home folder
00049                 char ch = user_jackdrc[strlen(user_jackdrc)-1];
00050 
00051                 if (('/' != ch) && ('\\' != ch))
00052                         strcat(user_jackdrc, "\\");
00053 
00054                 if (user_jackdrc[1] == ':')
00055                 {
00056                         // Assume we have a valid path
00057                         strcat(user_jackdrc, ".jackdrc");
00058                         strcpy(path_to_jackdrc, user_jackdrc);
00059 
00060                         ret = path_to_jackdrc;
00061                 }
00062                 else
00063                         path_to_jackdrc[0] = '\0';
00064         }
00065         else
00066                 path_to_jackdrc[0] = '\0';
00067 
00068         return (ret);
00069 }
00070 
00071 #else
00072 
00073 static char*
00074 find_path_to_jackdrc(char *path_to_jackdrc)
00075 {
00076         return 0;
00077 }
00078 
00079 #endif
00080 
00081 /* 'start_server_aux()' - this function might need to be modified (though probably
00082  * not) to cope with compilers other than MSVC (e.g. MinGW). The function
00083  * 'find_path_to_jackdrc()' might also need to be written for MinGW, though for
00084  * Cygwin, JackPosixServerLaunch.cpp can be used instead of this file.
00085  */
00086 
00087 #include <direct.h>
00088 
00089 static int start_server_aux(const char* server_name)
00090 {
00091     FILE*  fp      = 0;
00092     size_t pos     = 0;
00093     size_t result  = 0;
00094     int    i       = 0;
00095     int    good    = 0;
00096     int    ret     = 0;
00097     char*  command = 0;
00098     char** argv    = 0;
00099     char*  p;
00100     char*  back_slash;
00101     char*  forward_slash;
00102     char   arguments [256];
00103     char   buffer    [MAX_PATH];
00104     char   filename  [MAX_PATH];
00105     char   curr_wd   [MAX_PATH];
00106     char   temp_wd   [MAX_PATH];
00107 
00108         curr_wd[0] = '\0';
00109         if (find_path_to_jackdrc(filename))
00110                 fp = fopen(filename, "r");
00111 
00112         /* if still not found, check old config name for backwards compatability */
00113         /* JE - hopefully won't be needed for the Windows build
00114     if (!fp) {
00115         fp = fopen("/etc/jackd.conf", "r");
00116     }
00117     */
00118 
00119         if (fp) {
00120                 arguments[0] = '\0';
00121 
00122                 fgets(filename, MAX_PATH, fp);
00123                 _strlwr(filename);
00124                 if (p = strstr(filename, ".exe")) {
00125                         p += 4;
00126                         *p = '\0';
00127                         pos = (size_t)(p - filename);
00128                         fseek(fp, 0, SEEK_SET);
00129 
00130                         if (command = (char*)malloc(pos+1))
00131                                 ret = fread(command, 1, pos, fp);
00132 
00133                         if (ret && !ferror(fp)) {
00134                                 command[pos]  = '\0'; // NULL terminator
00135                                 back_slash    = strrchr(command, '\\');
00136                                 forward_slash = strrchr(command, '/');
00137                                 if (back_slash > forward_slash)
00138                                         p = back_slash + 1;
00139                                 else
00140                                         p = forward_slash + 1;
00141 
00142                                 strcpy(buffer, p);
00143                                 while (ret != 0 && ret != EOF) {
00144                                         strcat(arguments, buffer);
00145                                         strcat(arguments, " ");
00146                                         ret = fscanf(fp, "%s", buffer);
00147                                 }
00148 
00149                                 if (strlen(arguments) > 0) {
00150                                         good = 1;
00151                                 }
00152                         }
00153                 }
00154 
00155                 fclose(fp);
00156         }
00157 
00158     if (!good) {
00159                 strcpy(buffer, JACK_LOCATION "/jackd.exe");
00160                 command = (char*)malloc((strlen(buffer))+1);
00161                 strcpy(command, buffer);
00162         strncpy(arguments, "jackd.exe -S -d " JACK_DEFAULT_DRIVER, 255);
00163     }
00164 
00165     int  buffer_termination;
00166     bool verbose_mode = false;
00167     argv = (char**)malloc(255);
00168     pos  = 0;
00169 
00170     while (1) {
00171         /* insert -T and -n server_name in front of arguments */
00172         if (i == 1) {
00173             argv[i] = (char*)malloc(strlen ("-T") + 1);
00174             strcpy (argv[i++], "-T");
00175             if (server_name) {
00176                 size_t optlen = strlen("-n");
00177                 char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
00178                 strcpy(buf, "-n");
00179                 strcpy(buf + optlen, server_name);
00180                 argv[i++] = buf;
00181             }
00182         }
00183 
00184                 // Only get the next character if there's more than 1 character
00185                 if ((pos < strlen(arguments)) && (arguments[pos+1]) && (arguments[pos+1] != ' ')) {
00186                         strncpy(buffer, arguments + pos++, 1);
00187                         buffer_termination = 1;
00188                 } else {
00189                         buffer[0] = '\0';
00190                         buffer_termination = 0;
00191                 }
00192 
00193                 buffer[1] = '\0';
00194                 if (buffer[0] == '\"')
00195                         result = strcspn(arguments + pos, "\"");
00196                 else
00197                         result = strcspn(arguments + pos, " ");
00198 
00199         if (0 == result)
00200             break;
00201                 else
00202                 {
00203                         strcat(buffer, arguments + pos);
00204 
00205                         // Terminate the buffer
00206                         buffer[result + buffer_termination] = '\0';
00207                         if (buffer[0] == '\"') {
00208                                 strcat(buffer, "\"");
00209                                 ++result;
00210                         }
00211 
00212                         argv[i] = (char*)malloc(strlen(buffer) + 1);
00213                         strcpy(argv[i], buffer);
00214                         pos += (result + 1);
00215                         ++i;
00216 
00217                         if ((0 == strcmp(buffer, "-v")) || (0 == strcmp(buffer, "--verbose")))
00218                                 verbose_mode = true;
00219                 }
00220     }
00221 
00222         argv[i] = 0;
00223 
00224 #ifdef SUPPORT_PRE_1_9_8_SERVER
00225         // Get the current working directory
00226         if (_getcwd(curr_wd, MAX_PATH)) {
00227                 strcpy(temp_wd, command);
00228                 back_slash    = strrchr(temp_wd, '\\');
00229                 forward_slash = strrchr(temp_wd, '/');
00230                 if (back_slash > forward_slash)
00231                         p = back_slash;
00232                 else
00233                         p = forward_slash;
00234                 *p = '\0';
00235 
00236                 // Accommodate older versions of Jack (pre v1.9.8) which
00237                 // might need to be started from their installation folder.
00238                 _chdir(temp_wd);
00239         }
00240 #endif
00241 
00242         if (verbose_mode) {
00243                 // Launch the server with a console... (note that
00244                 // if the client is a console app, the server might
00245                 // also use the client's console)
00246                 ret = _spawnv(_P_NOWAIT, command, argv);
00247         } else {
00248                 // Launch the server silently... (without a console)
00249                 ret = _spawnv(_P_DETACH, command, argv);
00250         }
00251 
00252     Sleep(2500); // Give it some time to launch
00253 
00254         if ((-1) == ret)
00255                 fprintf(stderr, "Execution of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
00256 
00257         if (strlen(curr_wd)) {
00258                 // Change the cwd back to its original setting
00259                 _chdir(curr_wd);
00260         }
00261 
00262         if (command)
00263                 free(command);
00264 
00265         if (argv) {
00266                 for (i = 0; argv[i] != 0; i++)
00267                         free (argv[i]);
00268 
00269                 free(argv);
00270         }
00271 
00272         return (ret == (-1) ? false : true);
00273 }
00274 
00275 static int start_server(const char* server_name, jack_options_t options)
00276 {
00277         if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
00278                 return 1;
00279         }
00280 
00281         return (((-1) != (start_server_aux(server_name)) ? 0 : (-1)));
00282 }
00283 
00284 static int server_connect(const char* server_name)
00285 {
00286         JackClientChannel channel;
00287         int res = channel.ServerCheck(server_name);
00288         channel.Close();
00289         JackSleep(2000); // Added by JE - 02-01-2009 (gives
00290                          // the channel some time to close)
00291         return res;
00292 }
00293 
00294 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
00295 {
00296         if (server_connect(va->server_name) < 0) {
00297                 int trys;
00298                 if (start_server(va->server_name, options)) {
00299                         int my_status1 = *status | JackFailure | JackServerFailed;
00300                         *status = (jack_status_t)my_status1;
00301                         return -1;
00302                 }
00303                 trys = 5;
00304                 do {
00305                         Sleep(1000);
00306                         if (--trys < 0) {
00307                                 int my_status1 = *status | JackFailure | JackServerFailed;
00308                                 *status = (jack_status_t)my_status1;
00309                                 return -1;
00310                         }
00311                 } while (server_connect(va->server_name) < 0);
00312                 int my_status1 = *status | JackServerStarted;
00313                 *status = (jack_status_t)my_status1;
00314         }
00315 
00316         return 0;
00317 }