Jack2  1.9.8
JackWinServerLaunch.cpp
1 /*
2 Copyright (C) 2001-2003 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 Copyright (C) 2011 John Emmas
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include "JackChannel.h"
23 #include "JackLibGlobals.h"
24 #include "JackServerLaunch.h"
25 #include "JackPlatformPlug.h"
26 
27 using namespace Jack;
28 
29 #include <shlobj.h>
30 #include <process.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <io.h>
34 
35 #if defined(_MSC_VER) || defined(__MINGW__) || defined(__MINGW32__)
36 
37 static char*
38 find_path_to_jackdrc(char *path_to_jackdrc)
39 {
40  char user_jackdrc[1024];
41  char *ptr = NULL;
42  char *ret = NULL;
43 
44  user_jackdrc[0] = user_jackdrc[1] = 0; // Initialise
45 
46  if (S_OK == SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, user_jackdrc))
47  {
48  // The above call should have given us the path to the user's home folder
49  char ch = user_jackdrc[strlen(user_jackdrc)-1];
50 
51  if (('/' != ch) && ('\\' != ch))
52  strcat(user_jackdrc, "\\");
53 
54  if (user_jackdrc[1] == ':')
55  {
56  // Assume we have a valid path
57  strcat(user_jackdrc, ".jackdrc");
58  strcpy(path_to_jackdrc, user_jackdrc);
59 
60  ret = path_to_jackdrc;
61  }
62  else
63  path_to_jackdrc[0] = '\0';
64  }
65  else
66  path_to_jackdrc[0] = '\0';
67 
68  return (ret);
69 }
70 
71 #else
72 
73 static char*
74 find_path_to_jackdrc(char *path_to_jackdrc)
75 {
76  return 0;
77 }
78 
79 #endif
80 
81 /* 'start_server_aux()' - this function might need to be modified (though probably
82  * not) to cope with compilers other than MSVC (e.g. MinGW). The function
83  * 'find_path_to_jackdrc()' might also need to be written for MinGW, though for
84  * Cygwin, JackPosixServerLaunch.cpp can be used instead of this file.
85  */
86 
87 #include <direct.h>
88 
89 static int start_server_aux(const char* server_name)
90 {
91  FILE* fp = 0;
92  size_t pos = 0;
93  size_t result = 0;
94  int i = 0;
95  int good = 0;
96  int ret = 0;
97  char* command = 0;
98  char** argv = 0;
99  char* p;
100  char* back_slash;
101  char* forward_slash;
102  char arguments [256];
103  char buffer [MAX_PATH];
104  char filename [MAX_PATH];
105  char curr_wd [MAX_PATH];
106  char temp_wd [MAX_PATH];
107 
108  curr_wd[0] = '\0';
109  if (find_path_to_jackdrc(filename))
110  fp = fopen(filename, "r");
111 
112  /* if still not found, check old config name for backwards compatability */
113  /* JE - hopefully won't be needed for the Windows build
114  if (!fp) {
115  fp = fopen("/etc/jackd.conf", "r");
116  }
117  */
118 
119  if (fp) {
120  arguments[0] = '\0';
121 
122  fgets(filename, MAX_PATH, fp);
123  _strlwr(filename);
124  if (p = strstr(filename, ".exe")) {
125  p += 4;
126  *p = '\0';
127  pos = (size_t)(p - filename);
128  fseek(fp, 0, SEEK_SET);
129 
130  if (command = (char*)malloc(pos+1))
131  ret = fread(command, 1, pos, fp);
132 
133  if (ret && !ferror(fp)) {
134  command[pos] = '\0'; // NULL terminator
135  back_slash = strrchr(command, '\\');
136  forward_slash = strrchr(command, '/');
137  if (back_slash > forward_slash)
138  p = back_slash + 1;
139  else
140  p = forward_slash + 1;
141 
142  strcpy(buffer, p);
143  while (ret != 0 && ret != EOF) {
144  strcat(arguments, buffer);
145  strcat(arguments, " ");
146  ret = fscanf(fp, "%s", buffer);
147  }
148 
149  if (strlen(arguments) > 0) {
150  good = 1;
151  }
152  }
153  }
154 
155  fclose(fp);
156  }
157 
158  if (!good) {
159  strcpy(buffer, JACK_LOCATION "/jackd.exe");
160  command = (char*)malloc((strlen(buffer))+1);
161  strcpy(command, buffer);
162  strncpy(arguments, "jackd.exe -S -d " JACK_DEFAULT_DRIVER, 255);
163  }
164 
165  int buffer_termination;
166  bool verbose_mode = false;
167  argv = (char**)malloc(255);
168  pos = 0;
169 
170  while (1) {
171  /* insert -T and -n server_name in front of arguments */
172  if (i == 1) {
173  argv[i] = (char*)malloc(strlen ("-T") + 1);
174  strcpy (argv[i++], "-T");
175  if (server_name) {
176  size_t optlen = strlen("-n");
177  char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
178  strcpy(buf, "-n");
179  strcpy(buf + optlen, server_name);
180  argv[i++] = buf;
181  }
182  }
183 
184  // Only get the next character if there's more than 1 character
185  if ((pos < strlen(arguments)) && (arguments[pos+1]) && (arguments[pos+1] != ' ')) {
186  strncpy(buffer, arguments + pos++, 1);
187  buffer_termination = 1;
188  } else {
189  buffer[0] = '\0';
190  buffer_termination = 0;
191  }
192 
193  buffer[1] = '\0';
194  if (buffer[0] == '\"')
195  result = strcspn(arguments + pos, "\"");
196  else
197  result = strcspn(arguments + pos, " ");
198 
199  if (0 == result)
200  break;
201  else
202  {
203  strcat(buffer, arguments + pos);
204 
205  // Terminate the buffer
206  buffer[result + buffer_termination] = '\0';
207  if (buffer[0] == '\"') {
208  strcat(buffer, "\"");
209  ++result;
210  }
211 
212  argv[i] = (char*)malloc(strlen(buffer) + 1);
213  strcpy(argv[i], buffer);
214  pos += (result + 1);
215  ++i;
216 
217  if ((0 == strcmp(buffer, "-v")) || (0 == strcmp(buffer, "--verbose")))
218  verbose_mode = true;
219  }
220  }
221 
222  argv[i] = 0;
223 
224 #ifdef SUPPORT_PRE_1_9_8_SERVER
225  // Get the current working directory
226  if (_getcwd(curr_wd, MAX_PATH)) {
227  strcpy(temp_wd, command);
228  back_slash = strrchr(temp_wd, '\\');
229  forward_slash = strrchr(temp_wd, '/');
230  if (back_slash > forward_slash)
231  p = back_slash;
232  else
233  p = forward_slash;
234  *p = '\0';
235 
236  // Accommodate older versions of Jack (pre v1.9.8) which
237  // might need to be started from their installation folder.
238  _chdir(temp_wd);
239  }
240 #endif
241 
242  if (verbose_mode) {
243  // Launch the server with a console... (note that
244  // if the client is a console app, the server might
245  // also use the client's console)
246  ret = _spawnv(_P_NOWAIT, command, argv);
247  } else {
248  // Launch the server silently... (without a console)
249  ret = _spawnv(_P_DETACH, command, argv);
250  }
251 
252  Sleep(2500); // Give it some time to launch
253 
254  if ((-1) == ret)
255  fprintf(stderr, "Execution of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
256 
257  if (strlen(curr_wd)) {
258  // Change the cwd back to its original setting
259  _chdir(curr_wd);
260  }
261 
262  if (command)
263  free(command);
264 
265  if (argv) {
266  for (i = 0; argv[i] != 0; i++)
267  free (argv[i]);
268 
269  free(argv);
270  }
271 
272  return (ret == (-1) ? false : true);
273 }
274 
275 static int start_server(const char* server_name, jack_options_t options)
276 {
277  if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
278  return 1;
279  }
280 
281  return (((-1) != (start_server_aux(server_name)) ? 0 : (-1)));
282 }
283 
284 static int server_connect(const char* server_name)
285 {
286  JackClientChannel channel;
287  int res = channel.ServerCheck(server_name);
288  channel.Close();
289  JackSleep(2000); // Added by JE - 02-01-2009 (gives
290  // the channel some time to close)
291  return res;
292 }
293 
294 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
295 {
296  if (server_connect(va->server_name) < 0) {
297  int trys;
298  if (start_server(va->server_name, options)) {
299  int my_status1 = *status | JackFailure | JackServerFailed;
300  *status = (jack_status_t)my_status1;
301  return -1;
302  }
303  trys = 5;
304  do {
305  Sleep(1000);
306  if (--trys < 0) {
307  int my_status1 = *status | JackFailure | JackServerFailed;
308  *status = (jack_status_t)my_status1;
309  return -1;
310  }
311  } while (server_connect(va->server_name) < 0);
312  int my_status1 = *status | JackServerStarted;
313  *status = (jack_status_t)my_status1;
314  }
315 
316  return 0;
317 }