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