Jack2  1.9.8
JackWinNamedPipeServerChannel.cpp
00001 /*
00002  Copyright (C) 2004-2008 Grame
00003 
00004  This program is free software; you can redistribute it and/or modify
00005  it under the terms of the GNU Lesser General Public License as published by
00006  the Free Software Foundation; either version 2.1 of the License, or
00007  (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  GNU Lesser General Public License for more details.
00013 
00014  You should have received a copy of the GNU Lesser General Public License
00015  along with this program; if not, write to the Free Software
00016  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018  */
00019 
00020 
00021 #include "JackWinNamedPipeServerChannel.h"
00022 #include "JackNotification.h"
00023 #include "JackRequest.h"
00024 #include "JackServer.h"
00025 #include "JackLockedEngine.h"
00026 #include "JackGlobals.h"
00027 #include "JackClient.h"
00028 #include "JackNotification.h"
00029 #include "JackException.h"
00030 #include <assert.h>
00031 
00032 using namespace std;
00033 
00034 namespace Jack
00035 {
00036 
00037 HANDLE JackClientPipeThread::fMutex = NULL;  // Never released....
00038 
00039 // fRefNum = -1 correspond to already removed client
00040 
00041 JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient* pipe)
00042     :fPipe(pipe), fServer(NULL), fThread(this), fRefNum(0)
00043 {
00044     // First one allocated the static fMutex
00045     if (fMutex == NULL) {
00046         fMutex = CreateMutex(NULL, FALSE, NULL);
00047     }
00048 }
00049 
00050 JackClientPipeThread::~JackClientPipeThread()
00051 {
00052     jack_log("JackClientPipeThread::~JackClientPipeThread");
00053     delete fPipe;
00054 }
00055 
00056 int JackClientPipeThread::Open(JackServer* server)      // Open the Server/Client connection
00057 {
00058     // Start listening
00059     if (fThread.Start() != 0) {
00060         jack_error("Cannot start Jack server listener\n");
00061         return -1;
00062     }
00063 
00064     fServer = server;
00065     return 0;
00066 }
00067 
00068 void JackClientPipeThread::Close()                                      // Close the Server/Client connection
00069 {
00070     jack_log("JackClientPipeThread::Close %x %ld", this, fRefNum);
00071     /*
00072         TODO : solve WIN32 thread Kill issue
00073         This would hang.. since Close will be followed by a delete,
00074         all ressources will be deallocated at the end.
00075     */
00076 
00077     fThread.Kill();
00078     fPipe->Close();
00079     fRefNum = -1;
00080 }
00081 
00082 bool JackClientPipeThread::Execute()
00083 {
00084     try{
00085         jack_log("JackClientPipeThread::Execute");
00086         return (HandleRequest());
00087     } catch (JackQuitException& e) {
00088         jack_log("JackClientPipeThread::Execute JackQuitException");
00089         return false;
00090     }
00091 }
00092 
00093 bool JackClientPipeThread::HandleRequest()
00094 {
00095     // Read header
00096     JackRequest header;
00097     int res = header.Read(fPipe);
00098     bool ret = true;
00099 
00100     // Lock the global mutex
00101     if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED) {
00102         jack_error("JackClientPipeThread::HandleRequest: mutex wait error");
00103     }
00104 
00105     if (res < 0) {
00106         jack_error("HandleRequest: cannot read header");
00107         ClientKill();
00108         ret = false;
00109     } else {
00110 
00111         // Read data
00112         switch (header.fType) {
00113 
00114             case JackRequest::kClientCheck: {
00115                 jack_log("JackRequest::ClientCheck");
00116                 JackClientCheckRequest req;
00117                 JackClientCheckResult res;
00118                 if (req.Read(fPipe) == 0)
00119                     res.fResult = fServer->GetEngine()->ClientCheck(req.fName, req.fUUID, res.fName, req.fProtocol, req.fOptions, &res.fStatus);
00120                 res.Write(fPipe);
00121                 // Atomic ClientCheck followed by ClientOpen on same pipe
00122                 if (req.fOpen)
00123                     HandleRequest();
00124                 break;
00125             }
00126 
00127             case JackRequest::kClientOpen: {
00128                 jack_log("JackRequest::ClientOpen");
00129                 JackClientOpenRequest req;
00130                 JackClientOpenResult res;
00131                 if (req.Read(fPipe) == 0)
00132                     ClientAdd(req.fName, req.fPID, req.fUUID, &res.fSharedEngine, &res.fSharedClient, &res.fSharedGraph, &res.fResult);
00133                 res.Write(fPipe);
00134                 break;
00135             }
00136 
00137             case JackRequest::kClientClose: {
00138                 jack_log("JackRequest::ClientClose");
00139                 JackClientCloseRequest req;
00140                 JackResult res;
00141                 if (req.Read(fPipe) == 0)
00142                     res.fResult = fServer->GetEngine()->ClientExternalClose(req.fRefNum);
00143                 res.Write(fPipe);
00144                 ClientRemove();
00145                 ret = false;
00146                 break;
00147             }
00148 
00149             case JackRequest::kActivateClient: {
00150                 JackActivateRequest req;
00151                 JackResult res;
00152                 jack_log("JackRequest::ActivateClient");
00153                 if (req.Read(fPipe) == 0)
00154                     res.fResult = fServer->GetEngine()->ClientActivate(req.fRefNum, req.fIsRealTime);
00155                 res.Write(fPipe);
00156                 break;
00157             }
00158 
00159             case JackRequest::kDeactivateClient: {
00160                 jack_log("JackRequest::DeactivateClient");
00161                 JackDeactivateRequest req;
00162                 JackResult res;
00163                 if (req.Read(fPipe) == 0)
00164                     res.fResult = fServer->GetEngine()->ClientDeactivate(req.fRefNum);
00165                 res.Write(fPipe);
00166                 break;
00167             }
00168 
00169             case JackRequest::kRegisterPort: {
00170                 jack_log("JackRequest::RegisterPort");
00171                 JackPortRegisterRequest req;
00172                 JackPortRegisterResult res;
00173                 if (req.Read(fPipe) == 0)
00174                     res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fPortType, req.fFlags, req.fBufferSize, &res.fPortIndex);
00175                 res.Write(fPipe);
00176                 break;
00177             }
00178 
00179             case JackRequest::kUnRegisterPort: {
00180                 jack_log("JackRequest::UnRegisterPort");
00181                 JackPortUnRegisterRequest req;
00182                 JackResult res;
00183                 if (req.Read(fPipe) == 0)
00184                     res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex);
00185                 res.Write(fPipe);
00186                 break;
00187             }
00188 
00189             case JackRequest::kConnectNamePorts: {
00190                 jack_log("JackRequest::ConnectNamePorts");
00191                 JackPortConnectNameRequest req;
00192                 JackResult res;
00193                 if (req.Read(fPipe) == 0)
00194                     res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
00195                 res.Write(fPipe);
00196                 break;
00197             }
00198 
00199             case JackRequest::kDisconnectNamePorts: {
00200                 jack_log("JackRequest::DisconnectNamePorts");
00201                 JackPortDisconnectNameRequest req;
00202                 JackResult res;
00203                 if (req.Read(fPipe) == 0)
00204                     res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
00205                 res.Write(fPipe);
00206                 break;
00207             }
00208 
00209             case JackRequest::kConnectPorts: {
00210                 jack_log("JackRequest::ConnectPorts");
00211                 JackPortConnectRequest req;
00212                 JackResult res;
00213                 if (req.Read(fPipe) == 0)
00214                     res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
00215                 res.Write(fPipe);
00216                 break;
00217             }
00218 
00219             case JackRequest::kDisconnectPorts: {
00220                 jack_log("JackRequest::DisconnectPorts");
00221                 JackPortDisconnectRequest req;
00222                 JackResult res;
00223                 if (req.Read(fPipe) == 0)
00224                     res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
00225                 res.Write(fPipe);
00226                 break;
00227             }
00228 
00229             case JackRequest::kPortRename: {
00230                 jack_log("JackRequest::PortRename");
00231                 JackPortRenameRequest req;
00232                 JackResult res;
00233                 if (req.Read(fPipe) == 0)
00234                     res.fResult = fServer->GetEngine()->PortRename(req.fRefNum, req.fPort, req.fName);
00235                 res.Write(fPipe);
00236                 break;
00237             }
00238 
00239             case JackRequest::kSetBufferSize: {
00240                 jack_log("JackRequest::SetBufferSize");
00241                 JackSetBufferSizeRequest req;
00242                 JackResult res;
00243                 if (req.Read(fPipe) == 0)
00244                     res.fResult = fServer->SetBufferSize(req.fBufferSize);
00245                 res.Write(fPipe);
00246                 break;
00247             }
00248 
00249             case JackRequest::kSetFreeWheel: {
00250                 jack_log("JackRequest::SetFreeWheel");
00251                 JackSetFreeWheelRequest req;
00252                 JackResult res;
00253                 if (req.Read(fPipe) == 0)
00254                     res.fResult = fServer->SetFreewheel(req.fOnOff);
00255                 res.Write(fPipe);
00256                 break;
00257             }
00258 
00259             case JackRequest::kComputeTotalLatencies: {
00260                 jack_log("JackRequest::ComputeTotalLatencies");
00261                 JackComputeTotalLatenciesRequest req;
00262                 JackResult res;
00263                 if (req.Read(fPipe) == 0)
00264                     res.fResult = fServer->GetEngine()->ComputeTotalLatencies();
00265                 res.Write(fPipe);
00266                 break;
00267             }
00268 
00269             case JackRequest::kReleaseTimebase: {
00270                 jack_log("JackRequest::ReleaseTimebase");
00271                 JackReleaseTimebaseRequest req;
00272                 JackResult res;
00273                 if (req.Read(fPipe) == 0)
00274                     res.fResult = fServer->ReleaseTimebase(req.fRefNum);
00275                 res.Write(fPipe);
00276                 break;
00277             }
00278 
00279             case JackRequest::kSetTimebaseCallback: {
00280                 jack_log("JackRequest::SetTimebaseCallback");
00281                 JackSetTimebaseCallbackRequest req;
00282                 JackResult res;
00283                 if (req.Read(fPipe) == 0)
00284                     res.fResult = fServer->SetTimebaseCallback(req.fRefNum, req.fConditionnal);
00285                 res.Write(fPipe);
00286                 break;
00287             }
00288 
00289             case JackRequest::kGetInternalClientName: {
00290                 jack_log("JackRequest::GetInternalClientName");
00291                 JackGetInternalClientNameRequest req;
00292                 JackGetInternalClientNameResult res;
00293                 if (req.Read(fPipe) == 0)
00294                     res.fResult = fServer->GetEngine()->GetInternalClientName(req.fIntRefNum, res.fName);
00295                 res.Write(fPipe);
00296                 break;
00297             }
00298 
00299             case JackRequest::kInternalClientHandle: {
00300                 jack_log("JackRequest::InternalClientHandle");
00301                 JackInternalClientHandleRequest req;
00302                 JackInternalClientHandleResult res;
00303                 if (req.Read(fPipe) == 0)
00304                     res.fResult = fServer->GetEngine()->InternalClientHandle(req.fName, &res.fStatus, &res.fIntRefNum);
00305                 res.Write(fPipe);
00306                 break;
00307             }
00308 
00309             case JackRequest::kInternalClientLoad: {
00310                 jack_log("JackRequest::InternalClientLoad");
00311                 JackInternalClientLoadRequest req;
00312                 JackInternalClientLoadResult res;
00313                 if (req.Read(fPipe) == 0)
00314                     res.fResult = fServer->InternalClientLoad1(req.fName, req.fDllName, req.fLoadInitName, req.fOptions, &res.fIntRefNum, req.fUUID, &res.fStatus);
00315                 res.Write(fPipe);
00316                 break;
00317             }
00318 
00319             case JackRequest::kInternalClientUnload: {
00320                 jack_log("JackRequest::InternalClientUnload");
00321                 JackInternalClientUnloadRequest req;
00322                 JackInternalClientUnloadResult res;
00323                 if (req.Read(fPipe) == 0)
00324                     res.fResult = fServer->GetEngine()->InternalClientUnload(req.fIntRefNum, &res.fStatus);
00325                 res.Write(fPipe);
00326                 break;
00327             }
00328 
00329             case JackRequest::kNotification: {
00330                 jack_log("JackRequest::Notification");
00331                 JackClientNotificationRequest req;
00332                 if (req.Read(fPipe) == 0) {
00333                     if (req.fNotify == kQUIT) {
00334                         jack_log("JackRequest::Notification kQUIT");
00335                         throw JackQuitException();
00336                     } else {
00337                         fServer->Notify(req.fRefNum, req.fNotify, req.fValue);
00338                     }
00339                 }
00340                 break;
00341             }
00342 
00343             case JackRequest::kSessionNotify: {
00344                 jack_log("JackRequest::SessionNotify");
00345                 JackSessionNotifyRequest req;
00346                 if (req.Read(fPipe) == 0) {
00347                     fServer->GetEngine()->SessionNotify(req.fRefNum, req.fDst, req.fEventType, req.fPath, fPipe, NULL);
00348                 }
00349                 break;
00350             }
00351 
00352             case JackRequest::kSessionReply: {
00353                 jack_log("JackRequest::SessionReply");
00354                 JackSessionReplyRequest req;
00355                 JackResult res;
00356                 if (req.Read(fPipe) == 0) {
00357                     fServer->GetEngine()->SessionReply(req.fRefNum);
00358                     res.fResult = 0;
00359                 }
00360                 res.Write(fPipe);
00361                 break;
00362             }
00363 
00364             case JackRequest::kGetClientByUUID: {
00365                 jack_log("JackRequest::GetClientByUUID");
00366                 JackGetClientNameRequest req;
00367                 JackClientNameResult res;
00368                 if (req.Read(fPipe) == 0) {
00369                     fServer->GetEngine()->GetClientNameForUUID(req.fUUID, res.fName, &res.fResult);
00370                 }
00371                 res.Write(fPipe);
00372                 break;
00373             }
00374 
00375             case JackRequest::kGetUUIDByClient: {
00376                 jack_log("JackRequest::GetUUIDByClient");
00377                 JackGetUUIDRequest req;
00378                 JackUUIDResult res;
00379                 if (req.Read(fPipe) == 0) {
00380                     fServer->GetEngine()->GetUUIDForClientName(req.fName, res.fUUID, &res.fResult);
00381                 }
00382                 res.Write(fPipe);
00383                 break;
00384             }
00385 
00386             case JackRequest::kReserveClientName: {
00387                 jack_log("JackRequest::ReserveClientName");
00388                 JackReserveNameRequest req;
00389                 JackResult res;
00390                 if (req.Read(fPipe) == 0) {
00391                     fServer->GetEngine()->ReserveClientName(req.fName, req.fUUID, &res.fResult);
00392                 }
00393                 res.Write(fPipe);
00394                 break;
00395             }
00396 
00397             case JackRequest::kClientHasSessionCallback: {
00398                 jack_log("JackRequest::ClientHasSessionCallback");
00399                 JackClientHasSessionCallbackRequest req;
00400                 JackResult res;
00401                 if (req.Read(fPipe) == 0) {
00402                     fServer->GetEngine()->ClientHasSessionCallback(req.fName, &res.fResult);
00403                 }
00404                 res.Write(fPipe);
00405                 break;
00406             }
00407 
00408             default:
00409                 jack_log("Unknown request %ld", header.fType);
00410                 break;
00411         }
00412     }
00413 
00414     // Unlock the global mutex
00415     ReleaseMutex(fMutex);
00416     return ret;
00417 }
00418 
00419 void JackClientPipeThread::ClientAdd(char* name, int pid, int uuid, int* shared_engine, int* shared_client, int* shared_graph, int* result)
00420 {
00421     jack_log("JackClientPipeThread::ClientAdd %s", name);
00422     fRefNum = -1;
00423     *result = fServer->GetEngine()->ClientExternalOpen(name, pid, uuid, &fRefNum, shared_engine, shared_client, shared_graph);
00424 }
00425 
00426 void JackClientPipeThread::ClientRemove()
00427 {
00428     jack_log("JackClientPipeThread::ClientRemove ref = %d", fRefNum);
00429     /* TODO : solve WIN32 thread Kill issue
00430     Close();
00431     */
00432     fRefNum = -1;
00433     fPipe->Close();
00434 }
00435 
00436 void JackClientPipeThread::ClientKill()
00437 {
00438     jack_log("JackClientPipeThread::ClientKill ref = %d", fRefNum);
00439 
00440     if (fRefNum == -1) {        // Correspond to an already removed client.
00441         jack_log("Kill a closed client");
00442     } else if (fRefNum == 0) {  // Correspond to a still not opened client.
00443         jack_log("Kill a not opened client");
00444     } else {
00445         fServer->ClientKill(fRefNum);
00446     }
00447 
00448     Close();
00449 }
00450 
00451 JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel():fThread(this)
00452 {}
00453 
00454 JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel()
00455 {
00456     std::list<JackClientPipeThread*>::iterator it;
00457 
00458     for (it = fClientList.begin(); it !=  fClientList.end(); it++) {
00459         JackClientPipeThread* client = *it;
00460         client->Close();
00461         delete client;
00462     }
00463 }
00464 
00465 int JackWinNamedPipeServerChannel::Open(const char* server_name, JackServer* server)
00466 {
00467     jack_log("JackWinNamedPipeServerChannel::Open ");
00468     snprintf(fServerName, sizeof(fServerName), server_name);
00469 
00470     // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object
00471     if (fRequestListenPipe.Bind(jack_server_dir, server_name, 0) < 0) {
00472         jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
00473         return -1;
00474     }
00475 
00476     fServer = server;
00477     return 0;
00478 }
00479 
00480 void JackWinNamedPipeServerChannel::Close()
00481 {
00482     /* TODO : solve WIN32 thread Kill issue
00483     This would hang the server... since we are quitting it, its not really problematic,
00484     all ressources will be deallocated at the end.
00485 
00486     fRequestListenPipe.Close();
00487     fThread.Stop();
00488     */
00489 
00490     fRequestListenPipe.Close();
00491 }
00492 
00493 int JackWinNamedPipeServerChannel::Start()
00494 {
00495     if (fThread.Start() != 0) {
00496         jack_error("Cannot start Jack server listener");
00497         return -1;
00498     } else {
00499         return 0;
00500     }
00501 }
00502 
00503 void JackWinNamedPipeServerChannel::Stop()
00504 {
00505     fThread.Kill();
00506 }
00507 
00508 bool JackWinNamedPipeServerChannel::Init()
00509 {
00510     jack_log("JackWinNamedPipeServerChannel::Init ");
00511     JackWinNamedPipeClient* pipe;
00512 
00513     // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object
00514     if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
00515         jack_error("JackWinNamedPipeServerChannel::Init : cannot connect pipe");
00516         return false;
00517     } else {
00518         ClientAdd(pipe);
00519         return true;
00520     }
00521 }
00522 
00523 bool JackWinNamedPipeServerChannel::Execute()
00524 {
00525     JackWinNamedPipeClient* pipe;
00526 
00527     if (fRequestListenPipe.Bind(jack_server_dir, fServerName, 0) < 0) {
00528         jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
00529         return false;
00530     }
00531 
00532     if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
00533         jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe");
00534         return false;
00535     }
00536 
00537     ClientAdd(pipe);
00538     return true;
00539 }
00540 
00541 void JackWinNamedPipeServerChannel::ClientAdd(JackWinNamedPipeClient* pipe)
00542 {
00543     // Remove dead (= not running anymore) clients.
00544     std::list<JackClientPipeThread*>::iterator it = fClientList.begin();
00545     JackClientPipeThread* client;
00546 
00547     jack_log("ClientAdd size  %ld", fClientList.size());
00548 
00549     while (it != fClientList.end()) {
00550         client = *it;
00551         jack_log("Remove dead client = %x running =  %ld", client, client->IsRunning());
00552         if (client->IsRunning()) {
00553             it++;
00554         } else {
00555             it = fClientList.erase(it);
00556             delete client;
00557         }
00558     }
00559 
00560     client = new JackClientPipeThread(pipe);
00561     client->Open(fServer);
00562     // Here we are sure that the client is running (because it's thread is in "running" state).
00563     fClientList.push_back(client);
00564 }
00565 
00566 } // end of namespace
00567 
00568