Fix on Windows.
[jack2.git] / windows / JackWinNamedPipeServerChannel.cpp
blob34f5d42336168e44456811c07e9324afebbf759b
1 /*
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"
27 #include <assert.h>
29 using namespace std;
31 namespace Jack
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
42 if (fMutex == NULL) {
43 fMutex = CreateMutex(NULL, FALSE, NULL);
47 JackClientPipeThread::~JackClientPipeThread()
49 jack_log("JackClientPipeThread::~JackClientPipeThread");
50 delete fPipe;
53 int JackClientPipeThread::Open(JackServer* server) // Open the Server/Client connection
55 fServer = server;
57 // Start listening
58 if (fThread.Start() != 0) {
59 jack_error("Cannot start Jack server listener\n");
60 return -1;
61 } else {
62 return 0;
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.
75 fThread.Kill();
76 fPipe->Close();
77 fRefNum = -1;
80 bool JackClientPipeThread::Execute()
82 jack_log("JackClientPipeThread::Execute");
83 return(HandleRequest());
86 bool JackClientPipeThread::HandleRequest()
88 // Read header
89 JackRequest header;
90 int res = header.Read(fPipe);
91 bool ret = true;
93 // Lock the global mutex
94 if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED)
95 jack_error("JackClientPipeThread::HandleRequest: mutex wait error");
97 if (res < 0) {
98 jack_error("HandleRequest: cannot read header");
99 ClientKill();
100 ret = false;
101 } else {
103 // Read data
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);
112 res.Write(fPipe);
113 break;
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);
122 res.Write(fPipe);
123 break;
126 case JackRequest::kClientClose: {
127 jack_log("JackRequest::ClientClose");
128 JackClientCloseRequest req;
129 JackResult res;
130 if (req.Read(fPipe) == 0)
131 res.fResult = fServer->GetEngine()->ClientExternalClose(req.fRefNum);
132 res.Write(fPipe);
133 ClientRemove();
134 ret = false;
135 break;
138 case JackRequest::kActivateClient: {
139 JackActivateRequest req;
140 JackResult res;
141 jack_log("JackRequest::ActivateClient");
142 if (req.Read(fPipe) == 0)
143 res.fResult = fServer->GetEngine()->ClientActivate(req.fRefNum, req.fIsRealTime);
144 res.Write(fPipe);
145 break;
148 case JackRequest::kDeactivateClient: {
149 jack_log("JackRequest::DeactivateClient");
150 JackDeactivateRequest req;
151 JackResult res;
152 if (req.Read(fPipe) == 0)
153 res.fResult = fServer->GetEngine()->ClientDeactivate(req.fRefNum);
154 res.Write(fPipe);
155 break;
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);
164 res.Write(fPipe);
165 break;
168 case JackRequest::kUnRegisterPort: {
169 jack_log("JackRequest::UnRegisterPort");
170 JackPortUnRegisterRequest req;
171 JackResult res;
172 if (req.Read(fPipe) == 0)
173 res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex);
174 res.Write(fPipe);
175 break;
178 case JackRequest::kConnectNamePorts: {
179 jack_log("JackRequest::ConnectNamePorts");
180 JackPortConnectNameRequest req;
181 JackResult res;
182 if (req.Read(fPipe) == 0)
183 res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
184 res.Write(fPipe);
185 break;
188 case JackRequest::kDisconnectNamePorts: {
189 jack_log("JackRequest::DisconnectNamePorts");
190 JackPortDisconnectNameRequest req;
191 JackResult res;
192 if (req.Read(fPipe) == 0)
193 res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
194 res.Write(fPipe);
195 break;
198 case JackRequest::kConnectPorts: {
199 jack_log("JackRequest::ConnectPorts");
200 JackPortConnectRequest req;
201 JackResult res;
202 if (req.Read(fPipe) == 0)
203 res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
204 res.Write(fPipe);
205 break;
208 case JackRequest::kDisconnectPorts: {
209 jack_log("JackRequest::DisconnectPorts");
210 JackPortDisconnectRequest req;
211 JackResult res;
212 if (req.Read(fPipe) == 0)
213 res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
214 res.Write(fPipe);
215 break;
218 case JackRequest::kPortRename: {
219 jack_log("JackRequest::PortRename");
220 JackPortRenameRequest req;
221 JackResult res;
222 if (req.Read(fPipe) == 0)
223 res.fResult = fServer->GetEngine()->PortRename(req.fRefNum, req.fPort, req.fName);
224 res.Write(fPipe);
225 break;
228 case JackRequest::kSetBufferSize: {
229 jack_log("JackRequest::SetBufferSize");
230 JackSetBufferSizeRequest req;
231 JackResult res;
232 if (req.Read(fPipe) == 0)
233 res.fResult = fServer->SetBufferSize(req.fBufferSize);
234 res.Write(fPipe);
235 break;
238 case JackRequest::kSetFreeWheel: {
239 jack_log("JackRequest::SetFreeWheel");
240 JackSetFreeWheelRequest req;
241 JackResult res;
242 if (req.Read(fPipe) == 0)
243 res.fResult = fServer->SetFreewheel(req.fOnOff);
244 res.Write(fPipe);
245 break;
248 case JackRequest::kReleaseTimebase: {
249 jack_log("JackRequest::ReleaseTimebase");
250 JackReleaseTimebaseRequest req;
251 JackResult res;
252 if (req.Read(fPipe) == 0)
253 res.fResult = fServer->ReleaseTimebase(req.fRefNum);
254 res.Write(fPipe);
255 break;
258 case JackRequest::kSetTimebaseCallback: {
259 jack_log("JackRequest::SetTimebaseCallback");
260 JackSetTimebaseCallbackRequest req;
261 JackResult res;
262 if (req.Read(fPipe) == 0)
263 res.fResult = fServer->SetTimebaseCallback(req.fRefNum, req.fConditionnal);
264 res.Write(fPipe);
265 break;
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);
274 res.Write(fPipe);
275 break;
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);
284 res.Write(fPipe);
285 break;
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);
294 res.Write(fPipe);
295 break;
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);
304 res.Write(fPipe);
305 break;
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);
313 break;
316 default:
317 jack_log("Unknown request %ld", header.fType);
318 break;
322 /* TODO
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);
331 return ret;
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);
337 fRefNum = -1;
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
345 Close();
347 fRefNum = -1;
348 fPipe->Close();
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");
359 } else {
360 fServer->ClientKill(fRefNum);
363 Close();
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;
375 client->Close();
376 delete client;
380 int JackWinNamedPipeServerChannel::Open(const char* server_name, JackServer* server)
382 jack_log("JackWinNamedPipeServerChannel::Open ");
384 fServer = server;
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");
390 return false;
393 // Start listening
394 if (fThread.Start() != 0) {
395 jack_error("Cannot start Jack server listener\n");
396 goto error;
399 return 0;
401 error:
402 fRequestListenPipe.Close();
403 return -1;
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();
413 fThread.Stop();
416 fThread.Kill();
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");
428 return false;
429 } else {
430 ClientAdd(pipe);
431 return true;
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");
441 return false;
444 if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
445 jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe");
446 return false;
449 ClientAdd(pipe);
450 return true;
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()) {
462 client = *it;
463 jack_log("Remove dead client = %x running = %ld", client, client->IsRunning());
464 if (client->IsRunning()) {
465 it++;
466 } else {
467 it = fClientList.erase(it);
468 delete client;
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