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*
find_path_to_jackdrc(char * path_to_jackdrc)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*
find_path_to_jackdrc(char * path_to_jackdrc)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 
start_server_aux(const char * server_name)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 compatibility */
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 
start_server(const char * server_name,jack_options_t options)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 
server_connect(const char * server_name)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 
try_start_server(jack_varargs_t * va,jack_options_t options,jack_status_t * status)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 }
319