Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

499 lines
12KB

  1. /*
  2. * Carla Pipe utils
  3. * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or 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 General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_PIPE_UTILS_HPP_INCLUDED
  18. #define CARLA_PIPE_UTILS_HPP_INCLUDED
  19. #define WAIT_START_TIMEOUT 3000 /* ms */
  20. #define WAIT_ZOMBIE_TIMEOUT 3000 /* ms */
  21. #define WAIT_STEP 100 /* ms */
  22. #include "CarlaUtils.hpp"
  23. #include "CarlaString.hpp"
  24. #include <fcntl.h>
  25. #include <sys/wait.h>
  26. // -----------------------------------------------------------------------
  27. class CarlaPipeServer
  28. {
  29. protected:
  30. CarlaPipeServer()
  31. : fPipeRecv(-1),
  32. fPipeSend(-1),
  33. fPid(-1),
  34. fReading(false)
  35. {
  36. carla_debug("CarlaPipeServer::CarlaPipeServer()");
  37. }
  38. // -------------------------------------------------------------------
  39. public:
  40. virtual ~CarlaPipeServer()
  41. {
  42. carla_debug("CarlaPipeServer::~CarlaPipeServer()");
  43. stop();
  44. }
  45. void start(const char* const filename, const char* const arg1, const char* const arg2)
  46. {
  47. CARLA_SAFE_ASSERT_RETURN(filename != nullptr,)
  48. CARLA_SAFE_ASSERT_RETURN(arg1 != nullptr,)
  49. CARLA_SAFE_ASSERT_RETURN(arg2 != nullptr,)
  50. carla_debug("CarlaPipeServer::start(\"%s\", \"%s\", \"%s\"", filename, arg1, arg2);
  51. //----------------------------------------------------------------
  52. const char* argv[6];
  53. //----------------------------------------------------------------
  54. // argv[0] => filename
  55. argv[0] = filename;
  56. //----------------------------------------------------------------
  57. // argv[1-2] => args
  58. argv[1] = arg1;
  59. argv[2] = arg2;
  60. //----------------------------------------------------------------
  61. // argv[3-4] => pipes
  62. int pipe1[2]; // written by host process, read by plugin UI process
  63. int pipe2[2]; // written by plugin UI process, read by host process
  64. if (pipe(pipe1) != 0)
  65. {
  66. fail("pipe1 creation failed");
  67. return;
  68. }
  69. if (pipe(pipe2) != 0)
  70. {
  71. fail("pipe2 creation failed");
  72. return;
  73. }
  74. char uiPipeRecv[100+1];
  75. char uiPipeSend[100+1];
  76. std::snprintf(uiPipeRecv, 100, "%d", pipe1[0]); /* [0] means reading end */
  77. std::snprintf(uiPipeSend, 100, "%d", pipe2[1]); /* [1] means writting end */
  78. uiPipeRecv[100] = '\0';
  79. uiPipeSend[100] = '\0';
  80. argv[3] = uiPipeRecv; // reading end
  81. argv[4] = uiPipeSend; // writting end
  82. //----------------------------------------------------------------
  83. // argv[5] => NULL
  84. argv[5] = nullptr;
  85. //----------------------------------------------------------------
  86. // fork
  87. int ret = -1;
  88. if ((! fork_exec(argv, &ret)) || ret == -1)
  89. {
  90. close(pipe1[0]);
  91. close(pipe1[1]);
  92. close(pipe2[0]);
  93. close(pipe2[1]);
  94. fail("fork_exec() failed");
  95. return;
  96. }
  97. fPid = ret;
  98. /* fork duplicated the handles, close pipe ends that are used by the child process */
  99. close(pipe1[0]);
  100. close(pipe2[1]);
  101. fPipeSend = pipe1[1]; /* [1] means writting end */
  102. fPipeRecv = pipe2[0]; /* [0] means reading end */
  103. fcntl(fPipeRecv, F_SETFL, fcntl(fPipeRecv, F_GETFL) | O_NONBLOCK);
  104. //----------------------------------------------------------------
  105. // wait a while for child process to confirm it is alive
  106. char ch;
  107. for (int i=0; ;)
  108. {
  109. ret = read(fPipeRecv, &ch, 1);
  110. switch (ret)
  111. {
  112. case -1:
  113. if (errno == EAGAIN)
  114. {
  115. if (i < WAIT_START_TIMEOUT / WAIT_STEP)
  116. {
  117. carla_msleep(WAIT_STEP);
  118. i++;
  119. continue;
  120. }
  121. carla_stderr("we have waited for child with pid %d to appear for %.1f seconds and we are giving up", (int)fPid, (float)WAIT_START_TIMEOUT / 1000.0f);
  122. }
  123. else
  124. carla_stderr("read() failed: %s", strerror(errno));
  125. break;
  126. case 1:
  127. if (ch == '\n')
  128. // success
  129. return;
  130. carla_stderr("read() wrong first char '%c'", ch);
  131. break;
  132. default:
  133. carla_stderr("read() returned %d", ret);
  134. break;
  135. }
  136. break;
  137. }
  138. carla_stderr("force killing misbehaved child %d (start)", (int)fPid);
  139. if (kill(fPid, SIGKILL) == -1)
  140. {
  141. carla_stderr("kill() failed: %s (start)\n", strerror(errno));
  142. }
  143. /* wait a while child to exit, we dont like zombie processes */
  144. wait_child(fPid);
  145. }
  146. void stop()
  147. {
  148. carla_debug("CarlaPipeServer::stop()");
  149. if (fPipeSend == -1 || fPipeRecv == -1 || fPid == -1)
  150. return;
  151. write(fPipeSend, "quit\n", 5);
  152. waitChildClose();
  153. close(fPipeRecv);
  154. close(fPipeSend);
  155. fPipeRecv = -1;
  156. fPipeSend = -1;
  157. fPid = -1;
  158. }
  159. void idle()
  160. {
  161. char* locale = nullptr;
  162. for (;;)
  163. {
  164. char* const msg = readline();
  165. if (msg == nullptr)
  166. break;
  167. if (locale == nullptr)
  168. {
  169. locale = strdup(setlocale(LC_NUMERIC, nullptr));
  170. setlocale(LC_NUMERIC, "POSIX");
  171. }
  172. fReading = true;
  173. msgReceived(msg);
  174. fReading = false;
  175. std::free(msg);
  176. }
  177. if (locale != nullptr)
  178. {
  179. setlocale(LC_NUMERIC, locale);
  180. std::free(locale);
  181. }
  182. }
  183. // -------------------------------------------------------------------
  184. bool readNextLineAsBool(bool& value)
  185. {
  186. if (! fReading)
  187. return false;
  188. if (char* const msg = readline())
  189. {
  190. value = (std::strcmp(msg, "true") == 0);
  191. std::free(msg);
  192. return true;
  193. }
  194. return false;
  195. }
  196. bool readNextLineAsInt(int& value)
  197. {
  198. if (! fReading)
  199. return false;
  200. if (char* const msg = readline())
  201. {
  202. value = atoi(msg);
  203. std::free(msg);
  204. return true;
  205. }
  206. return false;
  207. }
  208. bool readNextLineAsFloat(float& value)
  209. {
  210. if (! fReading)
  211. return false;
  212. if (char* const msg = readline())
  213. {
  214. bool ret = (sscanf(msg, "%f", &value) == 1);
  215. std::free(msg);
  216. return ret;
  217. }
  218. return false;
  219. }
  220. bool readNextLineAsString(char*& value)
  221. {
  222. if (! fReading)
  223. return false;
  224. if (char* const msg = readline())
  225. {
  226. value = msg;
  227. return true;
  228. }
  229. return false;
  230. }
  231. void writeMsg(const char* const msg)
  232. {
  233. ::write(fPipeSend, msg, std::strlen(msg));
  234. }
  235. void writeMsg(const char* const msg, size_t size)
  236. {
  237. ::write(fPipeSend, msg, size);
  238. }
  239. void writeAndFixMsg(const char* const msg)
  240. {
  241. const size_t size = std::strlen(msg);
  242. char smsg[size+1];
  243. std::strcpy(smsg, msg);
  244. smsg[size-1] = '\n';
  245. smsg[size] = '\0';
  246. for (size_t i=0; i<size; ++i)
  247. {
  248. if (smsg[i] == '\n')
  249. smsg[i] = '\r';
  250. }
  251. ::write(fPipeSend, smsg, size+1);
  252. }
  253. void waitChildClose()
  254. {
  255. if (! wait_child(fPid))
  256. {
  257. carla_stderr2("force killing misbehaved child %d (exit)", (int)fPid);
  258. if (kill(fPid, SIGKILL) == -1)
  259. carla_stderr2("kill() failed: %s (exit)", strerror(errno));
  260. else
  261. wait_child(fPid);
  262. }
  263. }
  264. // -------------------------------------------------------------------
  265. protected:
  266. virtual void fail(const char* const error)
  267. {
  268. carla_stderr2(error);
  269. }
  270. virtual void msgReceived(const char* const msg) = 0;
  271. // -------------------------------------------------------------------
  272. private:
  273. int fPipeRecv; // the pipe end that is used for receiving messages from UI
  274. int fPipeSend; // the pipe end that is used for sending messages to UI
  275. pid_t fPid;
  276. bool fReading;
  277. CarlaString fTempBuf;
  278. // -------------------------------------------------------------------
  279. char* readline()
  280. {
  281. char ch;
  282. ssize_t ret;
  283. char buf[0xff+1];
  284. char* ptr = buf;
  285. fTempBuf.clear();
  286. buf[0xff] = '\0';
  287. for (int i=0;; ++i)
  288. {
  289. ret = read(fPipeRecv, &ch, 1);
  290. if (ret == 1 && ch != '\n')
  291. {
  292. if (ch == '\r')
  293. ch = '\n';
  294. *ptr++ = ch;
  295. if (i+1 == 0xff)
  296. {
  297. i = 0;
  298. ptr = buf;
  299. fTempBuf += buf;
  300. }
  301. continue;
  302. }
  303. if (fTempBuf.isNotEmpty() || ptr != buf)
  304. {
  305. if (ptr != buf)
  306. {
  307. *ptr = '\0';
  308. fTempBuf += buf;
  309. }
  310. return strdup((const char*)fTempBuf);
  311. }
  312. break;
  313. }
  314. return nullptr;
  315. }
  316. static bool fork_exec(const char* const argv[6], int* const retp)
  317. {
  318. pid_t ret = *retp = vfork();
  319. switch (ret)
  320. {
  321. case 0: /* child process */
  322. execvp(argv[0], (char* const*)argv);
  323. carla_stderr2("exec of UI failed: %s", strerror(errno));
  324. return false;
  325. case -1:
  326. carla_stderr2("fork() failed to create new process for plugin UI");
  327. return false;
  328. }
  329. return true;
  330. }
  331. static bool wait_child(const pid_t pid)
  332. {
  333. pid_t ret;
  334. int i;
  335. if (pid == -1)
  336. {
  337. carla_stderr2("Can't wait for pid -1");
  338. return false;
  339. }
  340. for (i = 0; i < WAIT_ZOMBIE_TIMEOUT / WAIT_STEP; ++i)
  341. {
  342. ret = waitpid(pid, NULL, WNOHANG);
  343. if (ret != 0)
  344. {
  345. if (ret == pid)
  346. return true;
  347. if (ret == -1)
  348. {
  349. carla_stderr2("waitpid(%d) failed: %s", (int)pid, strerror(errno));
  350. return false;
  351. }
  352. carla_stderr2("we have waited for child pid %d to exit but we got pid %d instead", (int)pid, (int)ret);
  353. return false;
  354. }
  355. carla_msleep(WAIT_STEP); /* wait 100 ms */
  356. }
  357. carla_stderr2("we have waited for child with pid %d to exit for %.1f seconds and we are giving up", (int)pid, (float)WAIT_START_TIMEOUT / 1000.0f);
  358. return false;
  359. }
  360. };
  361. // -----------------------------------------------------------------------
  362. class CarlaPipeClient
  363. {
  364. protected:
  365. CarlaPipeClient()
  366. {
  367. carla_debug("CarlaPipeClient::CarlaPipeClient()");
  368. }
  369. // -------------------------------------------------------------------
  370. public:
  371. virtual ~CarlaPipeClient()
  372. {
  373. carla_debug("CarlaPipeClient::~CarlaPipeClient()");
  374. stop();
  375. }
  376. void stop()
  377. {
  378. }
  379. };
  380. // -----------------------------------------------------------------------
  381. #endif // CARLA_PIPE_UTILS_HPP_INCLUDED