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.

CarlaPipeUtils.hpp 12KB

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