Jack2  1.9.9
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 
21 #include "JackConstants.h"
22 #include "JackChannel.h"
23 #include "JackLibGlobals.h"
24 #include "JackServerLaunch.h"
25 #include "JackPlatformPlug.h"
26 
27 using namespace Jack;
28 
29 #if defined(USE_LIBDBUS_AUTOLAUNCH)
30 
31 #include <dbus/dbus.h>
32 
33 static int start_server_dbus(const char* server_name)
34 {
35  DBusError err;
36  DBusConnection *conn;
37  DBusMessage *msg;
38 
39  // initialise the errors
40  dbus_error_init(&err);
41 
42  // connect to the bus
43  conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
44  if (dbus_error_is_set(&err)) {
45  fprintf(stderr, "Connection Error (%s)\n", err.message);
46  dbus_error_free(&err);
47  }
48  if (NULL == conn) {
49  return 1;
50  }
51 
52  msg = dbus_message_new_method_call(
53  "org.jackaudio.service", // target for the method call
54  "/org/jackaudio/Controller", // object to call on
55  "org.jackaudio.JackControl", // interface to call on
56  "StartServer"); // method name
57  if (NULL == msg) {
58  fprintf(stderr, "Message Null\n");
59  return 1;
60  }
61 
62  // send message and get a handle for a reply
63  if (!dbus_connection_send(conn, msg, NULL))
64  {
65  fprintf(stderr, "Out Of Memory!\n");
66  return 1;
67  }
68 
69  dbus_message_unref(msg);
70  dbus_connection_flush(conn);
71  dbus_error_free(&err);
72 
73  return 0;
74 }
75 
76 #elif defined(USE_CLASSIC_AUTOLAUNCH)
77 
78 /* Exec the JACK server in this process. Does not return. */
79 static void start_server_classic_aux(const char* server_name)
80 {
81  FILE* fp = 0;
82  char filename[255];
83  char arguments[255];
84  char buffer[255];
85  char* command = 0;
86  size_t pos = 0;
87  size_t result = 0;
88  char** argv = 0;
89  int i = 0;
90  int good = 0;
91  int ret;
92 
93  snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
94  fp = fopen(filename, "r");
95 
96  if (!fp) {
97  fp = fopen("/etc/jackdrc", "r");
98  }
99  /* if still not found, check old config name for backwards compatability */
100  if (!fp) {
101  fp = fopen("/etc/jackd.conf", "r");
102  }
103 
104  if (fp) {
105  arguments[0] = '\0';
106  ret = fscanf(fp, "%s", buffer);
107  while (ret != 0 && ret != EOF) {
108  strcat(arguments, buffer);
109  strcat(arguments, " ");
110  ret = fscanf(fp, "%s", buffer);
111  }
112  if (strlen(arguments) > 0) {
113  good = 1;
114  }
115  fclose(fp);
116  }
117 
118  if (!good) {
119  command = (char*)(JACK_LOCATION "/jackd");
120  strncpy(arguments, JACK_LOCATION "/jackd -T -d "JACK_DEFAULT_DRIVER, 255);
121  } else {
122  result = strcspn(arguments, " ");
123  command = (char*)malloc(result + 1);
124  strncpy(command, arguments, result);
125  command[result] = '\0';
126  }
127 
128  argv = (char**)malloc(255);
129 
130  while (1) {
131  /* insert -T and -nserver_name in front of arguments */
132  if (i == 1) {
133  argv[i] = (char*)malloc(strlen ("-T") + 1);
134  strcpy (argv[i++], "-T");
135  if (server_name) {
136  size_t optlen = strlen("-n");
137  char* buf = (char*)malloc(optlen + strlen(server_name) + 1);
138  strcpy(buf, "-n");
139  strcpy(buf + optlen, server_name);
140  argv[i++] = buf;
141  }
142  }
143 
144  result = strcspn(arguments + pos, " ");
145  if (result == 0) {
146  break;
147  }
148  argv[i] = (char*)malloc(result + 1);
149  strncpy(argv[i], arguments + pos, result);
150  argv[i][result] = '\0';
151  pos += result + 1;
152  ++i;
153  }
154  argv[i] = 0;
155  execv(command, argv);
156 
157  /* If execv() succeeds, it does not return. There's no point
158  * in calling jack_error() here in the child process. */
159  fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno));
160 }
161 
162 static int start_server_classic(const char* server_name)
163 {
164  /* The double fork() forces the server to become a child of
165  * init, which will always clean up zombie process state on
166  * termination. This even works in cases where the server
167  * terminates but this client does not.
168  *
169  * Since fork() is usually implemented using copy-on-write
170  * virtual memory tricks, the overhead of the second fork() is
171  * probably relatively small.
172  */
173  switch (fork()) {
174  case 0: /* child process */
175  switch (fork()) {
176  case 0: /* grandchild process */
177  start_server_classic_aux(server_name);
178  _exit(99); /* exec failed */
179  case - 1:
180  _exit(98);
181  default:
182  _exit(0);
183  }
184  case - 1: /* fork() error */
185  return 1; /* failed to start server */
186  }
187 
188  /* only the original parent process goes here */
189  return 0; /* (probably) successful */
190 }
191 
192 #endif
193 
194 static int start_server(const char* server_name, jack_options_t options)
195 {
196  if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) {
197  return 1;
198  }
199 
200 #if defined(USE_LIBDBUS_AUTOLAUNCH)
201  return start_server_dbus(server_name);
202 #elif defined(USE_CLASSIC_AUTOLAUNCH)
203  return start_server_classic(server_name);
204 #else
205  fprintf(stderr, "Automatic start of JACK server is disabled at configure time\n");
206  return 1;
207 #endif
208 }
209 
210 static int server_connect(char* server_name)
211 {
212  JackClientChannel channel;
213  int res = channel.ServerCheck(server_name);
214  channel.Close();
215  JackSleep(2000); // Added by JE - 02-01-2009 (gives
216  // the channel some time to close)
217  return res;
218 }
219 
220 int try_start_server(jack_varargs_t* va, jack_options_t options, jack_status_t* status)
221 {
222  if (server_connect(va->server_name) < 0) {
223  int trys;
224  if (start_server(va->server_name, options)) {
225  int my_status1 = *status | JackFailure | JackServerFailed;
226  *status = (jack_status_t)my_status1;
227  return -1;
228  }
229  trys = 5;
230  do {
231  sleep(1);
232  if (--trys < 0) {
233  int my_status1 = *status | JackFailure | JackServerFailed;
234  *status = (jack_status_t)my_status1;
235  return -1;
236  }
237  } while (server_connect(va->server_name) < 0);
238  int my_status1 = *status | JackServerStarted;
239  *status = (jack_status_t)my_status1;
240  }
241 
242  return 0;
243 }
244 
JackClientChannel using sockets.