/* Copyright (C) 2004-2006 Grame This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "JackWinNamedPipeServerChannel.h" #include "JackRequest.h" #include "JackServer.h" #include "JackEngine.h" #include "JackGlobals.h" #include "JackClient.h" #include using namespace std; namespace Jack { HANDLE JackClientPipeThread::fMutex = NULL; // never released.... // fRefNum = -1 correspond to already removed client JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient* pipe) : fPipe(pipe), fServer(NULL), fRefNum(0) { fThread = JackGlobals::MakeThread(this); if (fMutex == NULL) fMutex = CreateMutex(NULL, FALSE, NULL); } JackClientPipeThread::~JackClientPipeThread() { delete fPipe; delete fThread; } int JackClientPipeThread::Open(JackServer* server) // Open the Server/Client connection { fServer = server; // Start listening if (fThread->Start() != 0) { jack_error("Cannot start Jack server listener\n"); return -1; } else { return 0; } } void JackClientPipeThread::Close() // Close the Server/Client connection { fThread->Kill(); fPipe->Close(); fRefNum = -1; } bool JackClientPipeThread::Execute() { JackLog("JackClientPipeThread::Execute\n"); return (HandleRequest() == 0); } int JackClientPipeThread::HandleRequest() { // Read header JackRequest header; int res = header.Read(fPipe); int ret = 0; // Lock the global mutex if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED) jack_error("JackClientPipeThread::HandleRequest: mutex wait error"); if (res < 0) { jack_error("HandleRequest: cannot read header"); KillClient(); ret = -1; } else { // Read data switch (header.fType) { case JackRequest::kClientNew: { JackLog("JackRequest::ClientNew\n"); JackClientNewRequest req; JackClientNewResult res; if (req.Read(fPipe) == 0) AddClient(req.fName, &res.fSharedEngine, &res.fSharedClient, &res.fSharedPorts, &res.fResult); res.Write(fPipe); break; } case JackRequest::kClientClose: { JackLog("JackRequest::ClientClose\n"); JackClientCloseRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->ClientClose(req.fRefNum); res.Write(fPipe); RemoveClient(); break; } case JackRequest::kActivateClient: { JackActivateRequest req; JackResult res; JackLog("JackRequest::ActivateClient\n"); if (req.Read(fPipe) == 0) res.fResult = fServer->Activate(req.fRefNum); res.Write(fPipe); break; } case JackRequest::kDeactivateClient: { JackLog("JackRequest::DeactivateClient\n"); JackDeactivateRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->Deactivate(req.fRefNum); res.Write(fPipe); break; } case JackRequest::kRegisterPort: { JackLog("JackRequest::RegisterPort\n"); JackPortRegisterRequest req; JackPortRegisterResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fFlags, req.fBufferSize, &res.fPortIndex); res.Write(fPipe); break; } case JackRequest::kUnRegisterPort: { JackLog("JackRequest::UnRegisterPort\n"); JackPortUnRegisterRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex); res.Write(fPipe); break; } case JackRequest::kConnectNamePorts: { JackLog("JackRequest::ConnectPorts\n"); JackPortConnectNameRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst); res.Write(fPipe); break; } case JackRequest::kDisconnectNamePorts: { JackLog("JackRequest::DisconnectPorts\n"); JackPortDisconnectNameRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst); res.Write(fPipe); break; } case JackRequest::kConnectPorts: { JackLog("JackRequest::ConnectPorts\n"); JackPortConnectRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst); res.Write(fPipe); break; } case JackRequest::kDisconnectPorts: { JackLog("JackRequest::DisconnectPorts\n"); JackPortDisconnectRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst); res.Write(fPipe); break; } case JackRequest::kSetBufferSize: { JackLog("JackRequest::SetBufferSize\n"); JackSetBufferSizeRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->SetBufferSize(req.fBufferSize); res.Write(fPipe); break; } case JackRequest::kSetFreeWheel: { JackLog("JackRequest::SetFreeWheel\n"); JackSetFreeWheelRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->SetFreewheel(req.fOnOff); res.Write(fPipe); break; } case JackRequest::kReleaseTimebase: { JackLog("JackRequest::kReleaseTimebase\n"); JackReleaseTimebaseRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->ReleaseTimebase(req.fRefNum); res.Write(fPipe); break; } case JackRequest::kSetTimebaseCallback: { JackLog("JackRequest::kSetTimebaseCallback\n"); JackSetTimebaseCallbackRequest req; JackResult res; if (req.Read(fPipe) == 0) res.fResult = fServer->GetEngine()->SetTimebaseCallback(req.fRefNum, req.fConditionnal); res.Write(fPipe); break; } case JackRequest::kNotification: { JackLog("JackRequest::Notification\n"); JackClientNotificationRequest req; if (req.Read(fPipe) == 0) fServer->Notify(req.fRefNum, req.fNotify, req.fValue); break; } default: JackLog("Unknown request %ld\n", header.fType); break; } } // Unlock the global mutex ReleaseMutex(fMutex); return ret; } void JackClientPipeThread::AddClient(char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result) { JackLog("JackWinNamedPipeServerChannel::AddClient %s\n", name); fRefNum = -1; *result = fServer->GetEngine()->ClientNew(name, &fRefNum, shared_engine, shared_client, shared_ports); } void JackClientPipeThread::RemoveClient() { JackLog("JackWinNamedPipeServerChannel::RemoveClient ref = %d\n", fRefNum); Close(); } void JackClientPipeThread::KillClient() { JackLog("JackClientPipeThread::KillClient \n"); JackLog("JackWinNamedPipeServerChannel::KillClient ref = %d\n", fRefNum); if (fRefNum == -1) { // Correspond to an already removed client. JackLog("Kill a closed client\n"); } else if (fRefNum == 0) { // Correspond to a still not opened client. JackLog("Kill a not opened client\n"); } else { fServer->Notify(fRefNum, JackNotifyChannelInterface::kDeadClient, 0); } Close(); } JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel() { fThread = JackGlobals::MakeThread(this); } JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel() { delete fThread; } int JackWinNamedPipeServerChannel::Open(JackServer* server) { JackLog("JackWinNamedPipeServerChannel::Open \n"); fServer = server; // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object if (fRequestListenPipe.Bind(jack_server_dir, 0) < 0) { jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe"); return false; } // Start listening if (fThread->Start() != 0) { jack_error("Cannot start Jack server listener\n"); goto error; } return 0; error: fRequestListenPipe.Close(); return -1; } void JackWinNamedPipeServerChannel::Close() { fThread->Kill(); fRequestListenPipe.Close(); } bool JackWinNamedPipeServerChannel::Init() { JackLog("JackWinNamedPipeServerChannel::Init \n"); JackWinNamedPipeClient* pipe; // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) { jack_error("JackWinNamedPipeServerChannel::Init : cannot connect pipe"); return false; } else { AddClient(pipe); return true; } } bool JackWinNamedPipeServerChannel::Execute() { JackWinNamedPipeClient* pipe; if (fRequestListenPipe.Bind(jack_server_dir, 0) < 0) { jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe"); return false; } if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) { jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe"); return false; } AddClient(pipe); return true; } void JackWinNamedPipeServerChannel::AddClient(JackWinNamedPipeClient* pipe) { // Remove dead (= not running anymore) clients. std::list::iterator it = fClientList.begin(); JackClientPipeThread* client; while (it != fClientList.end()) { client = *it; if (client->IsRunning()) { it++; } else { JackLog("Remove client from list\n"); it = fClientList.erase(it); delete(client); } } client = new JackClientPipeThread(pipe); client->Open(fServer); // Here we are sure that the client is running (because it's thread is in "running" state). fClientList.push_back(client); } } // end of namespace