Jack2  1.9.10
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  result = strcspn(arguments + pos, " ");
152  if (result == 0) {
153  break;
154  }
155  argv[i] = (char*)malloc(result + 1);
156  strncpy(argv[i], arguments + pos, result);
157  argv[i][result] = '\0';
158  pos += result + 1;
159  ++i;
160  }
161  argv[i] = 0;
162  execv(command, argv);
163 
164  /* If execv() succeeds, it does not return. There's no point
165  * in calling jack_error() here in the child process. */
166  fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
167 }
168 
169 static int start_server_classic(const char* server_name)
170 {
171  /* The double fork() forces the server to become a child of
172  * init, which will always clean up zombie process state on
173  * termination. This even works in cases where the server
174  * terminates but this client does not.
175  *
176  * Since fork() is usually implemented using copy-on-write
177  * virtual memory tricks, the overhead of the second fork() is
178  * probably relatively small.
179  */
180 
181  int status;
182  pid_t first_child_pid;
183 
184  first_child_pid = fork();
185  switch (first_child_pid) {
186  case 0: /* child process */
187  switch (fork()) {
188  case 0: /* grandchild process */
189  start_server_classic_aux(server_name);
190  _exit(99); /* exec failed */
191  case - 1:
192  _exit(98);
193  default:
194  _exit(0);
195  }
196  case - 1: /* fork() error */
197  return 1; /* failed to start server */
198  }
199  waitpid(first_child_pid, &status, 0);
200 
201  /* only the original parent process goes here */
202  return 0; /* (probably) successful */
203 }
204 
205 #endif
206 
207 static int start_server(const char* server_name, jack_options_t options)
208 {
209  if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
210  return 1;
211  }
212 
213 #if defined(USE_LIBDBUS_AUTOLAUNCH)
214  return start_server_dbus(server_name);
215 #elif defined(USE_CLASSIC_AUTOLAUNCH)
216  return start_server_classic(server_name);
217 #else
218  fprintf(stderr, "Automatic start of JACK server is disabled at configure time\n");
219  return 1;
220 #endif
221 }
222 
223 static int server_connect(char* server_name)
224 {
225  JackClientChannel channel;
226  int res = channel.ServerCheck(server_name);
227  channel.Close();
228  JackSleep(2000); // Added by JE - 02-01-2009 (gives
229  // the channel some time to close)
230  return res;
231 }
232 
233 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
234 {
235  if (server_connect(va->server_name) < 0) {
236  int trys;
237  if (start_server(va->server_name, options)) {
238  int my_status1 = *status | JackFailure | JackServerFailed;
239  *status = (jack_status_t)my_status1;
240  return -1;
241  }
242  trys = 5;
243  do {
244  sleep(1);
245  if (--trys < 0) {
246  int my_status1 = *status | JackFailure | JackServerFailed;
247  *status = (jack_status_t)my_status1;
248  return -1;
249  }
250  } while (server_connect(va->server_name) < 0);
251  int my_status1 = *status | JackServerStarted;
252  *status = (jack_status_t)my_status1;
253  }
254 
255  return 0;
256 }
257 
258 #endif // !defined(WIN32) || defined(__CYGWIN__)
JackClientChannel using sockets.