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