jack2 codebase
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.

619 lines
21KB

  1. /*
  2. Copyright (C) 2004-2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "JackWinNamedPipeServerChannel.h"
  16. #include "JackNotification.h"
  17. #include "JackRequest.h"
  18. #include "JackServer.h"
  19. #include "JackLockedEngine.h"
  20. #include "JackGlobals.h"
  21. #include "JackClient.h"
  22. #include "JackNotification.h"
  23. #include "JackException.h"
  24. #include <assert.h>
  25. using namespace std;
  26. namespace Jack
  27. {
  28. HANDLE JackClientPipeThread::fMutex = NULL; // Never released....
  29. // fRefNum = -1 correspond to already removed client
  30. JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient* pipe)
  31. :fPipe(pipe), fServer(NULL), fDecoder(NULL), fThread(this), fRefNum(0)
  32. {
  33. // First one allocated the static fMutex
  34. if (fMutex == NULL) {
  35. fMutex = CreateMutex(NULL, FALSE, NULL);
  36. }
  37. }
  38. JackClientPipeThread::~JackClientPipeThread()
  39. {
  40. jack_log("JackClientPipeThread::~JackClientPipeThread");
  41. delete fPipe;
  42. }
  43. int JackClientPipeThread::Open(JackServer* server) // Open the Server/Client connection
  44. {
  45. // Start listening
  46. if (fThread.Start() != 0) {
  47. jack_error("Cannot start Jack server listener\n");
  48. return -1;
  49. }
  50. fDecoder = new JackRequestDecoder(server, this);
  51. fServer = server;
  52. return 0;
  53. }
  54. void JackClientPipeThread::Close() // Close the Server/Client connection
  55. {
  56. jack_log("JackClientPipeThread::Close %x %ld", this, fRefNum);
  57. /*
  58. TODO : solve WIN32 thread Kill issue
  59. This would hang.. since Close will be followed by a delete,
  60. all ressources will be deallocated at the end.
  61. */
  62. fThread.Kill();
  63. fPipe->Close();
  64. fRefNum = -1;
  65. delete fDecoder;
  66. fDecoder = NULL;
  67. }
  68. bool JackClientPipeThread::Execute()
  69. {
  70. try {
  71. jack_log("JackClientPipeThread::Execute");
  72. JackRequest header;
  73. int res = header.Read(fPipe);
  74. bool ret = true;
  75. // Lock the global mutex
  76. if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED) {
  77. jack_error("JackClientPipeThread::Execute : mutex wait error");
  78. }
  79. // Decode header
  80. if (res < 0) {
  81. jack_log("JackClientPipeThread::Execute : cannot decode header");
  82. ClientKill();
  83. ret = false;
  84. // Decode request
  85. } else if {fDecoder->HandleRequest(fPipe, header.fType) < 0) {
  86. jack_log("JackClientPipeThread::Execute : cannot decode request");
  87. }
  88. // Unlock the global mutex
  89. if (!ReleaseMutex(fMutex)) {
  90. jack_error("JackClientPipeThread::Execute : mutex release error");
  91. }
  92. return ret;
  93. } catch (JackQuitException& e) {
  94. jack_log("JackClientPipeThread::Execute : JackQuitException");
  95. return false;
  96. }
  97. }
  98. /*
  99. void JackClientPipeThread::ClientAdd(char* name, int pid, int uuid, int* shared_engine, int* shared_client, int* shared_graph, int* result)
  100. {
  101. jack_log("JackClientPipeThread::ClientAdd %s", name);
  102. fRefNum = -1;
  103. *result = fServer->GetEngine()->ClientExternalOpen(name, pid, uuid, &fRefNum, shared_engine, shared_client, shared_graph);
  104. }
  105. void JackClientPipeThread::ClientRemove()
  106. {
  107. jack_log("JackClientPipeThread::ClientRemove ref = %d", fRefNum);
  108. // TODO : solve WIN32 thread Kill issue
  109. //Close();
  110. //
  111. fRefNum = -1;
  112. fPipe->Close();
  113. }
  114. */
  115. void JackClientPipeThread::ClientAdd(detail::JackChannelTransactionInterface* socket, JackClientOpenRequest* req, JackClientOpenResult *res)
  116. {
  117. jack_info("JackClientPipeThread::ClientAdd %s", req->fName);
  118. fRefNum = -1;
  119. res->fResult = fServer->GetEngine()->ClientExternalOpen(req->fName, req->fPID, req->fUUID, &fRefNum, &res->fSharedEngine, &res->fSharedClient, &res->fSharedGraph);
  120. }
  121. void JackClientPipeThread::ClientRemove(detail::JackChannelTransactionInterface* socket_aux, int refnum)
  122. {
  123. jack_info("JackClientPipeThread::ClientRemove ref = %d", refnum);
  124. // TODO : solve WIN32 thread Kill issue
  125. //Close();
  126. //
  127. fRefNum = -1;
  128. fPipe->Close();
  129. }
  130. /*
  131. bool JackClientPipeThread::HandleRequest()
  132. {
  133. // Read header
  134. JackRequest header;
  135. int res = header.Read(fPipe);
  136. bool ret = true;
  137. // Lock the global mutex
  138. if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED) {
  139. jack_error("JackClientPipeThread::HandleRequest: mutex wait error");
  140. }
  141. if (res < 0) {
  142. jack_error("HandleRequest: cannot read header");
  143. ClientKill();
  144. ret = false;
  145. } else {
  146. // Read data
  147. switch (header.fType) {
  148. case JackRequest::kClientCheck: {
  149. jack_log("JackRequest::ClientCheck");
  150. JackClientCheckRequest req;
  151. JackClientCheckResult res;
  152. if (req.Read(fPipe) == 0)
  153. res.fResult = fServer->GetEngine()->ClientCheck(req.fName, req.fUUID, res.fName, req.fProtocol, req.fOptions, &res.fStatus);
  154. res.Write(fPipe);
  155. // Atomic ClientCheck followed by ClientOpen on same pipe
  156. if (req.fOpen)
  157. HandleRequest();
  158. break;
  159. }
  160. case JackRequest::kClientOpen: {
  161. jack_log("JackRequest::ClientOpen");
  162. JackClientOpenRequest req;
  163. JackClientOpenResult res;
  164. if (req.Read(fPipe) == 0)
  165. ClientAdd(req.fName, req.fPID, req.fUUID, &res.fSharedEngine, &res.fSharedClient, &res.fSharedGraph, &res.fResult);
  166. res.Write(fPipe);
  167. break;
  168. }
  169. case JackRequest::kClientClose: {
  170. jack_log("JackRequest::ClientClose");
  171. JackClientCloseRequest req;
  172. JackResult res;
  173. if (req.Read(fPipe) == 0)
  174. res.fResult = fServer->GetEngine()->ClientExternalClose(req.fRefNum);
  175. res.Write(fPipe);
  176. ClientRemove();
  177. ret = false;
  178. break;
  179. }
  180. case JackRequest::kActivateClient: {
  181. JackActivateRequest req;
  182. JackResult res;
  183. jack_log("JackRequest::ActivateClient");
  184. if (req.Read(fPipe) == 0)
  185. res.fResult = fServer->GetEngine()->ClientActivate(req.fRefNum, req.fIsRealTime);
  186. res.Write(fPipe);
  187. break;
  188. }
  189. case JackRequest::kDeactivateClient: {
  190. jack_log("JackRequest::DeactivateClient");
  191. JackDeactivateRequest req;
  192. JackResult res;
  193. if (req.Read(fPipe) == 0)
  194. res.fResult = fServer->GetEngine()->ClientDeactivate(req.fRefNum);
  195. res.Write(fPipe);
  196. break;
  197. }
  198. case JackRequest::kRegisterPort: {
  199. jack_log("JackRequest::RegisterPort");
  200. JackPortRegisterRequest req;
  201. JackPortRegisterResult res;
  202. if (req.Read(fPipe) == 0)
  203. res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fPortType, req.fFlags, req.fBufferSize, &res.fPortIndex);
  204. res.Write(fPipe);
  205. break;
  206. }
  207. case JackRequest::kUnRegisterPort: {
  208. jack_log("JackRequest::UnRegisterPort");
  209. JackPortUnRegisterRequest req;
  210. JackResult res;
  211. if (req.Read(fPipe) == 0)
  212. res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex);
  213. res.Write(fPipe);
  214. break;
  215. }
  216. case JackRequest::kConnectNamePorts: {
  217. jack_log("JackRequest::ConnectNamePorts");
  218. JackPortConnectNameRequest req;
  219. JackResult res;
  220. if (req.Read(fPipe) == 0)
  221. res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
  222. res.Write(fPipe);
  223. break;
  224. }
  225. case JackRequest::kDisconnectNamePorts: {
  226. jack_log("JackRequest::DisconnectNamePorts");
  227. JackPortDisconnectNameRequest req;
  228. JackResult res;
  229. if (req.Read(fPipe) == 0)
  230. res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
  231. res.Write(fPipe);
  232. break;
  233. }
  234. case JackRequest::kConnectPorts: {
  235. jack_log("JackRequest::ConnectPorts");
  236. JackPortConnectRequest req;
  237. JackResult res;
  238. if (req.Read(fPipe) == 0)
  239. res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
  240. res.Write(fPipe);
  241. break;
  242. }
  243. case JackRequest::kDisconnectPorts: {
  244. jack_log("JackRequest::DisconnectPorts");
  245. JackPortDisconnectRequest req;
  246. JackResult res;
  247. if (req.Read(fPipe) == 0)
  248. res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
  249. res.Write(fPipe);
  250. break;
  251. }
  252. case JackRequest::kPortRename: {
  253. jack_log("JackRequest::PortRename");
  254. JackPortRenameRequest req;
  255. JackResult res;
  256. if (req.Read(fPipe) == 0)
  257. res.fResult = fServer->GetEngine()->PortRename(req.fRefNum, req.fPort, req.fName);
  258. res.Write(fPipe);
  259. break;
  260. }
  261. case JackRequest::kSetBufferSize: {
  262. jack_log("JackRequest::SetBufferSize");
  263. JackSetBufferSizeRequest req;
  264. JackResult res;
  265. if (req.Read(fPipe) == 0)
  266. res.fResult = fServer->SetBufferSize(req.fBufferSize);
  267. res.Write(fPipe);
  268. break;
  269. }
  270. case JackRequest::kSetFreeWheel: {
  271. jack_log("JackRequest::SetFreeWheel");
  272. JackSetFreeWheelRequest req;
  273. JackResult res;
  274. if (req.Read(fPipe) == 0)
  275. res.fResult = fServer->SetFreewheel(req.fOnOff);
  276. res.Write(fPipe);
  277. break;
  278. }
  279. case JackRequest::kComputeTotalLatencies: {
  280. jack_log("JackRequest::ComputeTotalLatencies");
  281. JackComputeTotalLatenciesRequest req;
  282. JackResult res;
  283. if (req.Read(fPipe) == 0)
  284. res.fResult = fServer->GetEngine()->ComputeTotalLatencies();
  285. res.Write(fPipe);
  286. break;
  287. }
  288. case JackRequest::kReleaseTimebase: {
  289. jack_log("JackRequest::ReleaseTimebase");
  290. JackReleaseTimebaseRequest req;
  291. JackResult res;
  292. if (req.Read(fPipe) == 0)
  293. res.fResult = fServer->ReleaseTimebase(req.fRefNum);
  294. res.Write(fPipe);
  295. break;
  296. }
  297. case JackRequest::kSetTimebaseCallback: {
  298. jack_log("JackRequest::SetTimebaseCallback");
  299. JackSetTimebaseCallbackRequest req;
  300. JackResult res;
  301. if (req.Read(fPipe) == 0)
  302. res.fResult = fServer->SetTimebaseCallback(req.fRefNum, req.fConditionnal);
  303. res.Write(fPipe);
  304. break;
  305. }
  306. case JackRequest::kGetInternalClientName: {
  307. jack_log("JackRequest::GetInternalClientName");
  308. JackGetInternalClientNameRequest req;
  309. JackGetInternalClientNameResult res;
  310. if (req.Read(fPipe) == 0)
  311. res.fResult = fServer->GetEngine()->GetInternalClientName(req.fIntRefNum, res.fName);
  312. res.Write(fPipe);
  313. break;
  314. }
  315. case JackRequest::kInternalClientHandle: {
  316. jack_log("JackRequest::InternalClientHandle");
  317. JackInternalClientHandleRequest req;
  318. JackInternalClientHandleResult res;
  319. if (req.Read(fPipe) == 0)
  320. res.fResult = fServer->GetEngine()->InternalClientHandle(req.fName, &res.fStatus, &res.fIntRefNum);
  321. res.Write(fPipe);
  322. break;
  323. }
  324. case JackRequest::kInternalClientLoad: {
  325. jack_log("JackRequest::InternalClientLoad");
  326. JackInternalClientLoadRequest req;
  327. JackInternalClientLoadResult res;
  328. if (req.Read(fPipe) == 0)
  329. res.fResult = fServer->InternalClientLoad1(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus);
  330. res.Write(fPipe);
  331. break;
  332. }
  333. case JackRequest::kInternalClientUnload: {
  334. jack_log("JackRequest::InternalClientUnload");
  335. JackInternalClientUnloadRequest req;
  336. JackInternalClientUnloadResult res;
  337. if (req.Read(fPipe) == 0)
  338. res.fResult = fServer->GetEngine()->InternalClientUnload(req.fIntRefNum, &res.fStatus);
  339. res.Write(fPipe);
  340. break;
  341. }
  342. case JackRequest::kNotification: {
  343. jack_log("JackRequest::Notification");
  344. JackClientNotificationRequest req;
  345. if (req.Read(fPipe) == 0) {
  346. if (req.fNotify == kQUIT) {
  347. jack_log("JackRequest::Notification kQUIT");
  348. throw JackQuitException();
  349. } else {
  350. fServer->Notify(req.fRefNum, req.fNotify, req.fValue);
  351. }
  352. }
  353. break;
  354. }
  355. case JackRequest::kSessionNotify: {
  356. jack_log("JackRequest::SessionNotify");
  357. JackSessionNotifyRequest req;
  358. if (req.Read(fPipe) == 0) {
  359. fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, fPipe, NULL);
  360. }
  361. break;
  362. }
  363. case JackRequest::kSessionReply: {
  364. jack_log("JackRequest::SessionReply");
  365. JackSessionReplyRequest req;
  366. JackResult res;
  367. if (req.Read(fPipe) == 0) {
  368. fServer->GetEngine()->SessionReply(req.fRefNum);
  369. res.fResult = 0;
  370. }
  371. res.Write(fPipe);
  372. break;
  373. }
  374. case JackRequest::kGetClientByUUID: {
  375. jack_log("JackRequest::GetClientByUUID");
  376. JackGetClientNameRequest req;
  377. JackClientNameResult res;
  378. if (req.Read(fPipe) == 0) {
  379. fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult);
  380. }
  381. res.Write(fPipe);
  382. break;
  383. }
  384. case JackRequest::kGetUUIDByClient: {
  385. jack_log("JackRequest::GetUUIDByClient");
  386. JackGetUUIDRequest req;
  387. JackUUIDResult res;
  388. if (req.Read(fPipe) == 0) {
  389. fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult);
  390. }
  391. res.Write(fPipe);
  392. break;
  393. }
  394. case JackRequest::kReserveClientName: {
  395. jack_log("JackRequest::ReserveClientName");
  396. JackReserveNameRequest req;
  397. JackResult res;
  398. if (req.Read(fPipe) == 0) {
  399. fServer->GetEngine()->ReserveClientName(req.fName, req.fUUID, &res.fResult);
  400. }
  401. res.Write(fPipe);
  402. break;
  403. }
  404. case JackRequest::kClientHasSessionCallback: {
  405. jack_log("JackRequest::ClientHasSessionCallback");
  406. JackClientHasSessionCallbackRequest req;
  407. JackResult res;
  408. if (req.Read(fPipe) == 0) {
  409. fServer->GetEngine()->ClientHasSessionCallback(req.fName, &res.fResult);
  410. }
  411. res.Write(fPipe);
  412. break;
  413. }
  414. default:
  415. jack_log("Unknown request %ld", header.fType);
  416. break;
  417. }
  418. }
  419. // Unlock the global mutex
  420. ReleaseMutex(fMutex);
  421. return ret;
  422. }
  423. */
  424. void JackClientPipeThread::ClientKill()
  425. {
  426. jack_log("JackClientPipeThread::ClientKill ref = %d", fRefNum);
  427. if (fRefNum == -1) { // Correspond to an already removed client.
  428. jack_log("Kill a closed client");
  429. } else if (fRefNum == 0) { // Correspond to a still not opened client.
  430. jack_log("Kill a not opened client");
  431. } else {
  432. fServer->ClientKill(fRefNum);
  433. }
  434. Close();
  435. }
  436. JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel():fThread(this)
  437. {}
  438. JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel()
  439. {
  440. std::list<JackClientPipeThread*>::iterator it;
  441. for (it = fClientList.begin(); it != fClientList.end(); it++) {
  442. JackClientPipeThread* client = *it;
  443. client->Close();
  444. delete client;
  445. }
  446. }
  447. int JackWinNamedPipeServerChannel::Open(const char* server_name, JackServer* server)
  448. {
  449. jack_log("JackWinNamedPipeServerChannel::Open ");
  450. snprintf(fServerName, sizeof(fServerName), server_name);
  451. // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object
  452. if (fRequestListenPipe.Bind(jack_server_dir, server_name, 0) < 0) {
  453. jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
  454. return -1;
  455. }
  456. fServer = server;
  457. return 0;
  458. }
  459. void JackWinNamedPipeServerChannel::Close()
  460. {
  461. /* TODO : solve WIN32 thread Kill issue
  462. This would hang the server... since we are quitting it, its not really problematic,
  463. all ressources will be deallocated at the end.
  464. fRequestListenPipe.Close();
  465. fThread.Stop();
  466. */
  467. fRequestListenPipe.Close();
  468. }
  469. int JackWinNamedPipeServerChannel::Start()
  470. {
  471. if (fThread.Start() != 0) {
  472. jack_error("Cannot start Jack server listener");
  473. return -1;
  474. } else {
  475. return 0;
  476. }
  477. }
  478. void JackWinNamedPipeServerChannel::Stop()
  479. {
  480. fThread.Kill();
  481. }
  482. bool JackWinNamedPipeServerChannel::Init()
  483. {
  484. jack_log("JackWinNamedPipeServerChannel::Init");
  485. JackWinNamedPipeClient* pipe;
  486. // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object
  487. if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
  488. jack_error("JackWinNamedPipeServerChannel::Init : cannot connect pipe");
  489. return false;
  490. } else {
  491. ClientAdd(pipe);
  492. return true;
  493. }
  494. }
  495. bool JackWinNamedPipeServerChannel::Execute()
  496. {
  497. JackWinNamedPipeClient* pipe;
  498. if (fRequestListenPipe.Bind(jack_server_dir, fServerName, 0) < 0) {
  499. jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
  500. return false;
  501. }
  502. if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
  503. jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe");
  504. return false;
  505. }
  506. ClientAdd(pipe);
  507. return true;
  508. }
  509. void JackWinNamedPipeServerChannel::ClientAdd(JackWinNamedPipeClient* pipe)
  510. {
  511. // Remove dead (= not running anymore) clients.
  512. std::list<JackClientPipeThread*>::iterator it = fClientList.begin();
  513. JackClientPipeThread* client;
  514. jack_info("ClientAdd size %ld", fClientList.size());
  515. while (it != fClientList.end()) {
  516. client = *it;
  517. jack_info("Remove dead client = %x running = %ld", client, client->IsRunning());
  518. if (client->IsRunning()) {
  519. it++;
  520. } else {
  521. it = fClientList.erase(it);
  522. delete client;
  523. }
  524. }
  525. client = new JackClientPipeThread(pipe);
  526. client->Open(fServer);
  527. // Here we are sure that the client is running (because it's thread is in "running" state).
  528. fClientList.push_back(client);
  529. }
  530. } // end of namespace