Vuo  2.0.2
VuoRuntime.cc
Go to the documentation of this file.
1 
10 #include <getopt.h>
11 #include <mach-o/dyld.h> // for _NSGetExecutablePath()
12 #include <dirent.h>
13 #include <dlfcn.h>
14 
15 #include "VuoApp.h"
16 #include "VuoEventLoop.h"
17 #include "VuoException.hh"
18 #include "VuoRuntime.h"
21 #include "VuoRuntimeState.hh"
22 #include "module.h"
23 
24 extern "C"
25 {
26 
27 static VuoRuntimeState *runtimeState = NULL;
28 void *vuoRuntimeState = NULL;
29 
33 void vuoInit(int argc, char **argv)
34 {
35  bool doAppInit = false;
36  char *controlURL = NULL;
37  char *telemetryURL = NULL;
38  bool isPaused = false;
39  pid_t runnerPid = 0;
40  int runnerPipe = -1;
41  bool continueIfRunnerDies = false;
42  bool doPrintHelp = false;
43  bool doPrintLicenses = false;
44 
45  // parse commandline arguments
46  {
47  int getoptArgC = 0;
48  char **getoptArgV = (char **)malloc(sizeof(char *) * argc);
49  for(int i = 0; i < argc; ++i)
50  {
51  // Don't pass the OS X Process Serial Number argument to getopt, since it can't handle long arguments with a single hyphen.
52  if (strncmp(argv[i], "-psn_", 5) == 0)
53  {
54  // Since we have a process serial number, we can assume this is an exported app being invoked by LaunchServices.
55  // Therefore we need to initialize the app (so it shows up in the dock).
56  doAppInit = true;
57  continue;
58  }
59 
60  getoptArgV[getoptArgC++] = argv[i];
61  }
62 
63  static struct option options[] = {
64  {"help", no_argument, NULL, 0},
65  {"vuo-control", required_argument, NULL, 0},
66  {"vuo-telemetry", required_argument, NULL, 0},
67  {"vuo-pause", no_argument, NULL, 0},
68  {"vuo-loader", required_argument, NULL, 0},
69  {"vuo-runner-pipe", required_argument, NULL, 0},
70  {"vuo-continue-if-runner-dies", no_argument, NULL, 0},
71  {"vuo-licenses", no_argument, NULL, 0},
72  {"vuo-runner-pid", required_argument, NULL, 0},
73  {NULL, no_argument, NULL, 0}
74  };
75  int optionIndex=-1;
76  int ret;
77  while ((ret = getopt_long(getoptArgC, getoptArgV, "", options, &optionIndex)) != -1)
78  {
79  if (ret == '?')
80  continue;
81 
82  switch(optionIndex)
83  {
84  case 0: // --help
85  doPrintHelp = true;
86  break;
87  case 1: // --vuo-control
88  if (controlURL)
89  free(controlURL);
90  controlURL = strdup(optarg);
91  break;
92  case 2: // --vuo-telemetry
93  if (telemetryURL)
94  free(telemetryURL);
95  telemetryURL = strdup(optarg);
96  break;
97  case 3: // --vuo-pause
98  isPaused = true;
99  break;
100  case 4: // --vuo-loader (ignored, but added here to avoid "unrecognized option" warning)
101  break;
102  case 5: // --vuo-runner-pipe
103  runnerPipe = atoi(optarg);
104  break;
105  case 6: // --vuo-continue-if-runner-dies
106  continueIfRunnerDies = true;
107  break;
108  case 7: // --vuo-licenses
109  doPrintLicenses = true;
110  break;
111  case 8: // --vuo-runner-pid
112  runnerPid = atoi(optarg);
113  break;
114  }
115  }
116  free(getoptArgV);
117  }
118 
119  // macOS 10.14 no longer provides the `-psn_` argument, so use an alternate method to detect LaunchServices.
120  // launchd is pid 1.
121  if (!doAppInit && !controlURL && getppid() == 1)
122  doAppInit = true;
123 
124  // Get the exported executable path.
125  char rawExecutablePath[PATH_MAX+1];
126  uint32_t size = sizeof(rawExecutablePath);
127  _NSGetExecutablePath(rawExecutablePath, &size);
128 
129  if (doPrintHelp)
130  {
131  printf("Usage: %s [options]\n"
132  "Options:\n"
133  " --help Display this information.\n"
134  " --vuo-licenses Display license information.\n",
135  argv[0]);
136 
137  exit(0);
138  }
139  else if (doPrintLicenses)
140  {
141  printf("This composition may include software licensed under the following terms:\n\n");
142 
143  // Derive the path of the app bundle's "Licenses" directory from its executable path.
144  char licensesPath[PATH_MAX+1];
145  licensesPath[0] = 0;
146  if (strlen(VuoGetFrameworkPath()))
147  {
148  strncpy(licensesPath, VuoGetFrameworkPath(), PATH_MAX);
149  strncat(licensesPath, "/Vuo.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING "/Documentation/Licenses", PATH_MAX);
150  }
151  else if (strlen(VuoGetRunnerFrameworkPath()))
152  {
153  strncpy(licensesPath, VuoGetRunnerFrameworkPath(), PATH_MAX);
154  strncat(licensesPath, "/VuoRunner.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING "/Documentation/Licenses", PATH_MAX);
155  }
156 
157  bool foundLicenses = false;
158  if (licensesPath[0] && access(licensesPath, 0) == 0)
159  {
160  DIR *dirp = opendir(licensesPath);
161  struct dirent *dp;
162  while ((dp = readdir(dirp)) != NULL)
163  {
164  if (dp->d_name[0] == '.')
165  continue;
166 
167  printf("=== %s =====================================================\n\n",dp->d_name);
168 
169  size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
170  char licensePath[pathSize];
171  strlcpy(licensePath, licensesPath, pathSize);
172  strlcat(licensePath, "/", pathSize);
173  strlcat(licensePath, dp->d_name, pathSize);
174 
175  int fd = open(licensePath, O_RDONLY);
176  char data[1024];
177  int bytesRead;
178  while((bytesRead = read(fd, data, 1024)) > 0)
179  write(1, data, bytesRead);
180  close(fd);
181 
182  printf("\n\n\n");
183  foundLicenses = true;
184  }
185  closedir(dirp);
186  }
187 
188  if (!foundLicenses)
189  printf("(No license information found.)\n");
190 
191  free(controlURL);
192  free(telemetryURL);
193  exit(0);
194  }
195 
196  void *executableHandle = dlopen(rawExecutablePath, 0);
197  if (! executableHandle)
198  {
199  VUserLog("The composition couldn't be started because a handle to the executable couldn't be obtained : %s", dlerror());
200  free(controlURL);
201  free(telemetryURL);
202  return;
203  }
204 
206  executableHandle, NULL, doAppInit);
207 
208  dlclose(executableHandle);
209 
210  free(controlURL);
211  free(telemetryURL);
212 }
213 
232 void vuoInitInProcess(void *ZMQContext, const char *controlURL, const char *telemetryURL, bool isPaused, pid_t runnerPid,
233  int runnerPipe, bool continueIfRunnerDies, const char *workingDirectory,
234  void *compositionBinaryHandle, void *previousRuntimeState, bool doAppInit)
235 {
236  runtimeState = (VuoRuntimeState *)previousRuntimeState;
237  if (! runtimeState)
238  {
242  }
243 
244  vuoRuntimeState = (void *)runtimeState;
245 
246  VuoCompositionState *compositionState = new VuoCompositionState;
247  compositionState->runtimeState = runtimeState;
248  compositionState->compositionIdentifier = "";
250 
251  try
252  {
254  workingDirectory, compositionBinaryHandle);
255  }
256  catch (VuoException &e)
257  {
258  VUserLog("%s", e.what());
259  return;
260  }
261 
262  if (doAppInit)
263  {
264  typedef void (*vuoAppInitType)(bool requiresDockIcon);
265  vuoAppInitType vuoAppInit = (vuoAppInitType) dlsym(RTLD_SELF, "VuoApp_init");
266  if (vuoAppInit)
267  vuoAppInit(true);
268  }
269 
271 
272  // If the composition had a pending call to vuoStopComposition() when it was stopped, call it again.
275 
277 }
278 
286 void * vuoFini(void)
287 {
288  runtimeState->fini();
289  return (void *)runtimeState;
290 }
291 
296 {
297  delete (VuoRuntimeState *)runtimeState;
298 }
299 
303 typedef void (*VuoCompositionFiniCallback)(void);
304 
310 {
311  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
312  if (r)
314  else
316 }
317 
322 pid_t vuoGetRunnerPid(VuoCompositionState *compositionState)
323 {
324  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
325  if (r)
326  return r->getRunnerPid();
327  else
328  return -1;
329 }
330 
336 {
337  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
338  if (r)
340 }
341 
347 {
348  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
349  if (r)
351 }
352 
358 {
359  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
360  if (r)
361  r->disableTermination();
362 }
363 
369 {
370  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
371  if (r)
372  r->enableTermination();
373 }
374 
381 {
382  return runtimeState->isStopped();
383 }
384 
385 } // extern "C"