Jack2 1.9.12

JackPosixServerLaunch.cpp
1 /*
2 Copyright (C) 2001-2003 Paul Davis
3 Copyright (C) 2004-2008 Grame
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 #if !defined(WIN32) || defined(__CYGWIN__)
21
22 #ifdef PTHREAD_WIN32 // Added by JE - 13-02-2010
23 #include <ptw32/pthread.h> // Makes sure we #include the ptw32 version for
24 #endif // consistency - even though we won't need it !
25
26 #include "JackConstants.h"
27 #include "JackChannel.h"
28 #include "JackLibGlobals.h"
29 #include "JackServerLaunch.h"
30 #include "JackPlatformPlug.h"
31
32 #include <sys/wait.h>
33
34 using namespace Jack;
35
36 #if defined(USE_LIBDBUS_AUTOLAUNCH)
37
38 #include <dbus/dbus.h>
39
40 static int start_server_dbus(const char* server_name)
41 {
42 DBusError err;
43 DBusConnection *conn;
44 DBusMessage *msg;
45
46 // initialise the errors
47 dbus_error_init(&err);
48
49 // connect to the bus
50 conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
51 if (dbus_error_is_set(&err)) {
52 fprintf(stderr, "Connection Error (%s)\n", err.message);
53 dbus_error_free(&err);
54 }
55 if (NULL == conn) {
56 return 1;
57 }
58
59 msg = dbus_message_new_method_call(
60 "org.jackaudio.service", // target for the method call
61 "/org/jackaudio/Controller", // object to call on
62 "org.jackaudio.JackControl", // interface to call on
63 "StartServer"); // method name
64 if (NULL == msg) {
65 fprintf(stderr, "Message Null\n");
66 return 1;
67 }
68
69 // send message and get a handle for a reply
70 if (!dbus_connection_send(conn, msg, NULL))
71 {
72 fprintf(stderr, "Out Of Memory!\n");
73 return 1;
74 }
75
76 dbus_message_unref(msg);
77 dbus_connection_flush(conn);
78 dbus_error_free(&err);
79
80 return 0;
81 }
82
83 #elif defined(USE_CLASSIC_AUTOLAUNCH)
84
85 /* Exec the JACK server in this process. Does not return. */
86 static void start_server_classic_aux(const char* server_name)
87 {
88 FILE* fp = 0;
89 char filename[255];
90 char arguments[255];
91 char buffer[255];
92 char* command = 0;
93 size_t pos = 0;
94 size_t result = 0;
95 char** argv = 0;
96 int i = 0;
97 int good = 0;
98 int res;
99
100 snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
101 fp = fopen(filename, "r");
102
103 if (!fp) {
104 fp = fopen("/etc/jackdrc", "r");
105 }
106 /* if still not found, check old config name for backwards compatability */
107 if (!fp) {
108 fp = fopen("/etc/jackd.conf", "r");
109 }
110
111 if (fp) {
112 arguments[0] = '\0';
113 res = fscanf(fp, "%s", buffer);
114 while (res != 0 && res != EOF) {
115 strcat(arguments, buffer);
116 strcat(arguments, " ");
117 res = fscanf(fp, "%s", buffer);
118 }
119 if (strlen(arguments) > 0) {
120 good = 1;
121 }
122 fclose(fp);
123 }
124
125 if (!good) {
126 command = (char*)(JACK_LOCATION "/jackd");
127 strncpy(arguments, JACK_LOCATION "/jackd -T -d " JACK_DEFAULT_DRIVER, 255);
128 } else {
129 result = strcspn(arguments, " ");
130 command = (char*)malloc(result + 1);
131 strncpy(command, arguments, result);
132 command[result] = '\0';
133 }
134
135 argv = (char**)malloc(255);
136
137 while (1) {
138 /* insert -T and -nserver_name in front of arguments */
139 if (i == 1) {
140 argv[i] = (char*)malloc(strlen ("-T") + 1);
141 strcpy (argv[i++], "-T");
142 if (server_name) {
143 size_t optlen = strlen("-n");
144 char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
145 strcpy(buf, "-n");
146 strcpy(buf + optlen, server_name);
147 argv[i++] = buf;
148 }
149 }
150
151 /* skip whitespace */
152 while (pos < strlen(arguments) && arguments[pos] && arguments[pos] == ' ') {
153 ++pos;
154 }
155
156 if (pos >= strlen(arguments)) {
157 break;
158 }
159
160 if (arguments[pos] == '\"') {
161 ++pos;
162 result = strcspn(arguments + pos, "\"");
163 } else {
164 result = strcspn(arguments + pos, " ");
165 }
166
167 if (0 == result) {
168 break;
169 }
170
171 argv[i] = (char*)malloc(result + 1);
172 strncpy(argv[i], arguments + pos, result);
173 argv[i][result] = '\0';
174 pos += result + 1;
175
176 if (++i > 253) {
177 break;
178 }
179 }
180
181 argv[i] = 0;
182 execv(command, argv);
183
184 /* If execv() succeeds, it does not return. There's no point
185 * in calling jack_error() here in the child process. */
186 fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
187 }
188
189 static int start_server_classic(const char* server_name)
190 {
191 /* The double fork() forces the server to become a child of
192 * init, which will always clean up zombie process state on
193 * termination. This even works in cases where the server
194 * terminates but this client does not.
195 *
196 * Since fork() is usually implemented using copy-on-write
197 * virtual memory tricks, the overhead of the second fork() is
198 * probably relatively small.
199 */
200
201 int status;
202 pid_t first_child_pid;
203
204 first_child_pid = fork();
205 switch (first_child_pid) {
206 case 0: /* child process */
207 switch (fork()) {
208 case 0: /* grandchild process */
209 start_server_classic_aux(server_name);
210 _exit(99); /* exec failed */
211 case - 1:
212 _exit(98);
213 default:
214 _exit(0);
215 }
216 case - 1: /* fork() error */
217 return 1; /* failed to start server */
218 }
219 waitpid(first_child_pid, &status, 0);
220
221 /* only the original parent process goes here */
222 return 0; /* (probably) successful */
223 }
224
225 #endif
226
227 static int start_server(const char* server_name, jack_options_t options)
228 {
229 if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
230 return 1;
231 }
232
233 #if defined(USE_LIBDBUS_AUTOLAUNCH)
234 return start_server_dbus(server_name);
235 #elif defined(USE_CLASSIC_AUTOLAUNCH)
236 return start_server_classic(server_name);
237 #else
238 fprintf(stderr, "Automatic start of JACK server is disabled at configure time\n");
239 return 1;
240 #endif
241 }
242
243 static int server_connect(char* server_name)
244 {
245 JackClientChannel channel;
246 int res = channel.ServerCheck(server_name);
247 channel.Close();
248 JackSleep(2000); // Added by JE - 02-01-2009 (gives
249 // the channel some time to close)
250 return res;
251 }
252
253 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
254 {
255 if (server_connect(va->server_name) < 0) {
256 int trys;
257 if (start_server(va->server_name, options)) {
258 int my_status1 = *status | JackFailure | JackServerFailed;
259 *status = (jack_status_t)my_status1;
260 return -1;
261 }
262 trys = 5;
263 do {
264 sleep(1);
265 if (--trys < 0) {
266 int my_status1 = *status | JackFailure | JackServerFailed;
267 *status = (jack_status_t)my_status1;
268 return -1;
269 }
270 } while (server_connect(va->server_name) < 0);
271 int my_status1 = *status | JackServerStarted;
272 *status = (jack_status_t)my_status1;
273 }
274
275 return 0;
276 }
277
278 #endif // !defined(WIN32) || defined(__CYGWIN__)
jack_varargs_t
Definition: varargs.h:34
Jack::JackSocketClientChannel
JackClientChannel using sockets.
Definition: JackSocketClientChannel.h:37