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__)