JackMachServerChannel.cpp

00001 /*
00002 Copyright (C) 2004-2006 Grame  
00003 
00004 This program is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 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 General Public License for more details.
00013 
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #include "JackMachServerChannel.h"
00021 #include "JackRPCEngineServer.c"
00022 #include "JackError.h"
00023 #include "JackServer.h"
00024 #include "JackMachThread.h"
00025 #include "JackEngine.h"
00026 
00027 using namespace std;
00028 
00029 namespace Jack
00030 {
00031 
00032 map<mach_port_t, JackMachServerChannel*> JackMachServerChannel::fPortTable;
00033 
00034 JackMachServerChannel::JackMachServerChannel()
00035 {
00036     fThread = new JackMachThread(this);
00037 }
00038 
00039 JackMachServerChannel::~JackMachServerChannel()
00040 {
00041     delete fThread;
00042 }
00043 
00044 int JackMachServerChannel::Open(JackServer* server)
00045 {
00046     JackLog("JackMachServerChannel::Open\n");
00047 
00048     if (!fServerPort.AllocatePort(jack_server_entry, 16)) { // 16 is the max possible value
00049         jack_error("Cannot check in Jack server");
00050         return -1;
00051     }
00052 
00053     if (fThread->Start() != 0) {
00054         jack_error("Cannot start Jack server listener");
00055         return -1;
00056     }
00057 
00058     fServer = server;
00059     fPortTable[fServerPort.GetPort()] = this;
00060     return 0;
00061 }
00062 
00063 void JackMachServerChannel::Close()
00064 {
00065     JackLog("JackMachServerChannel::Close\n");
00066     fThread->Kill();
00067     fServerPort.DestroyPort();
00068 }
00069 
00070 JackEngine* JackMachServerChannel::GetEngine()
00071 {
00072     return fServer->GetEngine();
00073 }
00074 
00075 JackServer* JackMachServerChannel::GetServer()
00076 {
00077     return fServer;
00078 }
00079 
00080 void JackMachServerChannel::AddClient(char* name, mach_port_t* private_port, int* shared_engine, int* shared_client, int* shared_graph, int* result)
00081 {
00082     int refnum = -1;
00083     *result = GetEngine()->ClientNew(name, &refnum, shared_engine, shared_client, shared_graph);
00084 
00085     if (*result == 0) {
00086         mach_port_t port = fServerPort.AddPort();
00087         if (port != 0) {
00088             fClientTable[port] = refnum;
00089             fPortTable[port] = this;
00090             *private_port = port;
00091         } else {
00092             jack_error("Cannot create private client mach port");
00093             *result = -1;
00094         }
00095     } else {
00096         jack_error("Cannot create new client");
00097     }
00098 }
00099 
00100 void JackMachServerChannel::RemoveClient(mach_port_t private_port, int refnum)
00101 {
00102     GetEngine()->ClientClose(refnum);
00103     fClientTable.erase(private_port);
00104 
00105     // Hum, hum....
00106     kern_return_t res;
00107     if ((res = mach_port_destroy(mach_task_self(), private_port)) != KERN_SUCCESS) {
00108         jack_error("server_rpc_jack_client_close mach_port_destroy %s", mach_error_string(res));
00109     }
00110 }
00111 
00112 void JackMachServerChannel::KillClient(mach_port_t private_port)
00113 {
00114     JackLog("JackMachServerChannel::KillClient\n");
00115     int refnum = fClientTable[private_port];
00116     assert(refnum > 0);
00117     fServer->Notify(refnum, JackNotifyChannelInterface::kDeadClient, 0);
00118     fClientTable.erase(private_port);
00119 
00120     // Hum, hum....
00121     kern_return_t res;
00122     if ((res = mach_port_destroy(mach_task_self(), private_port)) != KERN_SUCCESS) {
00123         jack_error("server_rpc_jack_client_close mach_port_destroy %s", mach_error_string(res));
00124     }
00125 }
00126 
00127 boolean_t JackMachServerChannel::MessageHandler(mach_msg_header_t* Request, mach_msg_header_t* Reply)
00128 {
00129     if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
00130         JackLog("MACH_NOTIFY_NO_SENDERS %ld\n", Request->msgh_local_port);
00131         JackMachServerChannel* channel = JackMachServerChannel::fPortTable[Request->msgh_local_port];
00132         assert(channel);
00133         channel->KillClient(Request->msgh_local_port);
00134     } else {
00135         JackRPCEngine_server(Request, Reply);
00136     }
00137     return true;
00138 }
00139 
00140 bool JackMachServerChannel::Execute()
00141 {
00142     kern_return_t res;
00143     if ((res = mach_msg_server(MessageHandler, 1024, fServerPort.GetPortSet(), 0)) != KERN_SUCCESS) {
00144         JackLog("JackMachServerChannel::Execute: err = %s\n", mach_error_string(res));
00145     }
00146     //return (res == KERN_SUCCESS);  mach_msg_server can fail if the client reply port is not valid anymore (crashed client)
00147     return true;
00148 }
00149 
00150 } // end of namespace
00151 
00152 

Generated on Wed Jan 10 11:42:45 2007 for Jackdmp by  doxygen 1.4.5