2 Copyright (C) 2004-2006 Grame
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.
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.
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.
20 #include "JackWinNamedPipeServerChannel.h"
21 #include "JackNotification.h"
22 #include "JackRequest.h"
23 #include "JackServer.h"
24 #include "JackLockedEngine.h"
25 #include "JackGlobals.h"
26 #include "JackClient.h"
34 HANDLE
JackClientPipeThread::fMutex
= NULL
; // Never released....
36 // fRefNum = -1 correspond to already removed client
38 JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient
* pipe
)
39 :fPipe(pipe
), fServer(NULL
), fThread(this), fRefNum(0)
41 // First one allocated the static fMutex
43 fMutex
= CreateMutex(NULL
, FALSE
, NULL
);
47 JackClientPipeThread::~JackClientPipeThread()
49 jack_log("JackClientPipeThread::~JackClientPipeThread");
53 int JackClientPipeThread::Open(JackServer
* server
) // Open the Server/Client connection
58 if (fThread
.Start() != 0) {
59 jack_error("Cannot start Jack server listener\n");
66 void JackClientPipeThread::Close() // Close the Server/Client connection
68 jack_log("JackClientPipeThread::Close %x %ld", this, fRefNum
);
70 TODO : solve WIN32 thread Kill issue
71 This would hang.. since Close will be followed by a delete,
72 all ressources will be desallocated at the end.
80 bool JackClientPipeThread::Execute()
82 jack_log("JackClientPipeThread::Execute");
83 return(HandleRequest());
86 bool JackClientPipeThread::HandleRequest()
90 int res
= header
.Read(fPipe
);
93 // Lock the global mutex
94 if (WaitForSingleObject(fMutex
, INFINITE
) == WAIT_FAILED
)
95 jack_error("JackClientPipeThread::HandleRequest: mutex wait error");
98 jack_error("HandleRequest: cannot read header");
104 switch (header
.fType
) {
106 case JackRequest::kClientCheck
: {
107 jack_log("JackRequest::ClientCheck");
108 JackClientCheckRequest req
;
109 JackClientCheckResult res
;
110 if (req
.Read(fPipe
) == 0)
111 res
.fResult
= fServer
->GetEngine()->ClientCheck(req
.fName
, res
.fName
, req
.fProtocol
, req
.fOptions
, &res
.fStatus
);
116 case JackRequest::kClientOpen
: {
117 jack_log("JackRequest::ClientOpen");
118 JackClientOpenRequest req
;
119 JackClientOpenResult res
;
120 if (req
.Read(fPipe
) == 0)
121 ClientAdd(req
.fName
, req
.fPID
, &res
.fSharedEngine
, &res
.fSharedClient
, &res
.fSharedGraph
, &res
.fResult
);
126 case JackRequest::kClientClose
: {
127 jack_log("JackRequest::ClientClose");
128 JackClientCloseRequest req
;
130 if (req
.Read(fPipe
) == 0)
131 res
.fResult
= fServer
->GetEngine()->ClientExternalClose(req
.fRefNum
);
138 case JackRequest::kActivateClient
: {
139 JackActivateRequest req
;
141 jack_log("JackRequest::ActivateClient");
142 if (req
.Read(fPipe
) == 0)
143 res
.fResult
= fServer
->GetEngine()->ClientActivate(req
.fRefNum
, req
.fIsRealTime
);
148 case JackRequest::kDeactivateClient
: {
149 jack_log("JackRequest::DeactivateClient");
150 JackDeactivateRequest req
;
152 if (req
.Read(fPipe
) == 0)
153 res
.fResult
= fServer
->GetEngine()->ClientDeactivate(req
.fRefNum
);
158 case JackRequest::kRegisterPort
: {
159 jack_log("JackRequest::RegisterPort");
160 JackPortRegisterRequest req
;
161 JackPortRegisterResult res
;
162 if (req
.Read(fPipe
) == 0)
163 res
.fResult
= fServer
->GetEngine()->PortRegister(req
.fRefNum
, req
.fName
, req
.fPortType
, req
.fFlags
, req
.fBufferSize
, &res
.fPortIndex
);
168 case JackRequest::kUnRegisterPort
: {
169 jack_log("JackRequest::UnRegisterPort");
170 JackPortUnRegisterRequest req
;
172 if (req
.Read(fPipe
) == 0)
173 res
.fResult
= fServer
->GetEngine()->PortUnRegister(req
.fRefNum
, req
.fPortIndex
);
178 case JackRequest::kConnectNamePorts
: {
179 jack_log("JackRequest::ConnectNamePorts");
180 JackPortConnectNameRequest req
;
182 if (req
.Read(fPipe
) == 0)
183 res
.fResult
= fServer
->GetEngine()->PortConnect(req
.fRefNum
, req
.fSrc
, req
.fDst
);
188 case JackRequest::kDisconnectNamePorts
: {
189 jack_log("JackRequest::DisconnectNamePorts");
190 JackPortDisconnectNameRequest req
;
192 if (req
.Read(fPipe
) == 0)
193 res
.fResult
= fServer
->GetEngine()->PortDisconnect(req
.fRefNum
, req
.fSrc
, req
.fDst
);
198 case JackRequest::kConnectPorts
: {
199 jack_log("JackRequest::ConnectPorts");
200 JackPortConnectRequest req
;
202 if (req
.Read(fPipe
) == 0)
203 res
.fResult
= fServer
->GetEngine()->PortConnect(req
.fRefNum
, req
.fSrc
, req
.fDst
);
208 case JackRequest::kDisconnectPorts
: {
209 jack_log("JackRequest::DisconnectPorts");
210 JackPortDisconnectRequest req
;
212 if (req
.Read(fPipe
) == 0)
213 res
.fResult
= fServer
->GetEngine()->PortDisconnect(req
.fRefNum
, req
.fSrc
, req
.fDst
);
218 case JackRequest::kPortRename
: {
219 jack_log("JackRequest::PortRename");
220 JackPortRenameRequest req
;
222 if (req
.Read(fPipe
) == 0)
223 res
.fResult
= fServer
->GetEngine()->PortRename(req
.fRefNum
, req
.fPort
, req
.fName
);
228 case JackRequest::kSetBufferSize
: {
229 jack_log("JackRequest::SetBufferSize");
230 JackSetBufferSizeRequest req
;
232 if (req
.Read(fPipe
) == 0)
233 res
.fResult
= fServer
->SetBufferSize(req
.fBufferSize
);
238 case JackRequest::kSetFreeWheel
: {
239 jack_log("JackRequest::SetFreeWheel");
240 JackSetFreeWheelRequest req
;
242 if (req
.Read(fPipe
) == 0)
243 res
.fResult
= fServer
->SetFreewheel(req
.fOnOff
);
248 case JackRequest::kReleaseTimebase
: {
249 jack_log("JackRequest::ReleaseTimebase");
250 JackReleaseTimebaseRequest req
;
252 if (req
.Read(fPipe
) == 0)
253 res
.fResult
= fServer
->ReleaseTimebase(req
.fRefNum
);
258 case JackRequest::kSetTimebaseCallback
: {
259 jack_log("JackRequest::SetTimebaseCallback");
260 JackSetTimebaseCallbackRequest req
;
262 if (req
.Read(fPipe
) == 0)
263 res
.fResult
= fServer
->SetTimebaseCallback(req
.fRefNum
, req
.fConditionnal
);
268 case JackRequest::kGetInternalClientName
: {
269 jack_log("JackRequest::GetInternalClientName");
270 JackGetInternalClientNameRequest req
;
271 JackGetInternalClientNameResult res
;
272 if (req
.Read(fPipe
) == 0)
273 res
.fResult
= fServer
->GetEngine()->GetInternalClientName(req
.fIntRefNum
, res
.fName
);
278 case JackRequest::kInternalClientHandle
: {
279 jack_log("JackRequest::InternalClientHandle");
280 JackInternalClientHandleRequest req
;
281 JackInternalClientHandleResult res
;
282 if (req
.Read(fPipe
) == 0)
283 res
.fResult
= fServer
->GetEngine()->InternalClientHandle(req
.fName
, &res
.fStatus
, &res
.fIntRefNum
);
288 case JackRequest::kInternalClientLoad
: {
289 jack_log("JackRequest::InternalClientLoad");
290 JackInternalClientLoadRequest req
;
291 JackInternalClientLoadResult res
;
292 if (req
.Read(fPipe
) == 0)
293 res
.fResult
= fServer
->InternalClientLoad(req
.fName
, req
.fDllName
, req
.fLoadInitName
, req
.fOptions
, &res
.fIntRefNum
, &res
.fStatus
);
298 case JackRequest::kInternalClientUnload
: {
299 jack_log("JackRequest::InternalClientUnload");
300 JackInternalClientUnloadRequest req
;
301 JackInternalClientUnloadResult res
;
302 if (req
.Read(fPipe
) == 0)
303 res
.fResult
= fServer
->GetEngine()->InternalClientUnload(req
.fIntRefNum
, &res
.fStatus
);
308 case JackRequest::kNotification
: {
309 jack_log("JackRequest::Notification");
310 JackClientNotificationRequest req
;
311 if (req
.Read(fPipe
) == 0)
312 fServer
->Notify(req
.fRefNum
, req
.fNotify
, req
.fValue
);
317 jack_log("Unknown request %ld", header
.fType
);
323 // Issued by JackEngine::ReleaseRefnum when temporary mode is used
324 if (JackServerGlobals::fKilled) {
325 kill(JackTools::GetPID(), SIGINT);
329 // Unlock the global mutex
330 ReleaseMutex(fMutex
);
334 void JackClientPipeThread::ClientAdd(char* name
, int pid
, int* shared_engine
, int* shared_client
, int* shared_graph
, int* result
)
336 jack_log("JackClientPipeThread::ClientAdd %s", name
);
338 *result
= fServer
->GetEngine()->ClientExternalOpen(name
, pid
, &fRefNum
, shared_engine
, shared_client
, shared_graph
);
341 void JackClientPipeThread::ClientRemove()
343 jack_log("JackClientPipeThread::ClientRemove ref = %d", fRefNum
);
344 /* TODO : solve WIN32 thread Kill issue
351 void JackClientPipeThread::ClientKill()
353 jack_log("JackClientPipeThread::ClientKill ref = %d", fRefNum
);
355 if (fRefNum
== -1) { // Correspond to an already removed client.
356 jack_log("Kill a closed client");
357 } else if (fRefNum
== 0) { // Correspond to a still not opened client.
358 jack_log("Kill a not opened client");
360 fServer
->ClientKill(fRefNum
);
366 JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel():fThread(this)
369 JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel()
371 std::list
<JackClientPipeThread
*>::iterator it
;
373 for (it
= fClientList
.begin(); it
!= fClientList
.end(); it
++) {
374 JackClientPipeThread
* client
= *it
;
380 int JackWinNamedPipeServerChannel::Open(const char* server_name
, JackServer
* server
)
382 jack_log("JackWinNamedPipeServerChannel::Open ");
385 snprintf(fServerName
, sizeof(fServerName
), server_name
);
387 // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object
388 if (fRequestListenPipe
.Bind(jack_server_dir
, server_name
, 0) < 0) {
389 jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
394 if (fThread
.Start() != 0) {
395 jack_error("Cannot start Jack server listener\n");
402 fRequestListenPipe
.Close();
406 void JackWinNamedPipeServerChannel::Close()
408 /* TODO : solve WIN32 thread Kill issue
409 This would hang the server... since we are quitting it, its not really problematic,
410 all ressources will be desallocated at the end.
412 fRequestListenPipe.Close();
417 fRequestListenPipe
.Close();
420 bool JackWinNamedPipeServerChannel::Init()
422 jack_log("JackWinNamedPipeServerChannel::Init ");
423 JackWinNamedPipeClient
* pipe
;
425 // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object
426 if ((pipe
= fRequestListenPipe
.AcceptClient()) == NULL
) {
427 jack_error("JackWinNamedPipeServerChannel::Init : cannot connect pipe");
435 bool JackWinNamedPipeServerChannel::Execute()
437 JackWinNamedPipeClient
* pipe
;
439 if (fRequestListenPipe
.Bind(jack_server_dir
, fServerName
, 0) < 0) {
440 jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
444 if ((pipe
= fRequestListenPipe
.AcceptClient()) == NULL
) {
445 jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe");
453 void JackWinNamedPipeServerChannel::ClientAdd(JackWinNamedPipeClient
* pipe
)
455 // Remove dead (= not running anymore) clients.
456 std::list
<JackClientPipeThread
*>::iterator it
= fClientList
.begin();
457 JackClientPipeThread
* client
;
459 jack_log("ClientAdd size %ld", fClientList
.size());
461 while (it
!= fClientList
.end()) {
463 jack_log("Remove dead client = %x running = %ld", client
, client
->IsRunning());
464 if (client
->IsRunning()) {
467 it
= fClientList
.erase(it
);
472 client
= new JackClientPipeThread(pipe
);
473 client
->Open(fServer
);
474 // Here we are sure that the client is running (because it's thread is in "running" state).
475 fClientList
.push_back(client
);
478 } // end of namespace