Jack2 1.9.6

JackMachServerChannel.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 #include "JackTools.h"
00021 #include "JackMachServerChannel.h"
00022 #include "JackRPCEngineServer.c"
00023 #include "JackError.h"
00024 #include "JackServer.h"
00025 #include "JackLockedEngine.h"
00026 #include "JackNotification.h"
00027 #include "JackServerGlobals.h"
00028 
00029 using namespace std;
00030 
00031 namespace Jack
00032 {
00033 
00034 map<mach_port_t, JackMachServerChannel*> JackMachServerChannel::fPortTable;
00035 
00036 JackMachServerChannel::JackMachServerChannel():fThread(this)
00037 {}
00038 
00039 JackMachServerChannel::~JackMachServerChannel()
00040 {}
00041 
00042 int JackMachServerChannel::Open(const char* server_name, JackServer* server)
00043 {
00044     jack_log("JackMachServerChannel::Open");
00045     char jack_server_entry_name[512];
00046     snprintf(jack_server_entry_name, sizeof(jack_server_entry_name), "%s.%d_%s", jack_server_entry, JackTools::GetUID(), server_name);
00047 
00048     if (!fServerPort.AllocatePort(jack_server_entry_name, 16)) { // 16 is the max possible value
00049         jack_error("Cannot check in Jack server");
00050         return -1;
00051     }
00052 
00053     fServer = server;
00054     fPortTable[fServerPort.GetPort()] = this;
00055     return 0;
00056 }
00057 
00058 void JackMachServerChannel::Close()
00059 {
00060     jack_log("JackMachServerChannel::Close");
00061  #ifdef MAC_OS_X_VERSION_10_5
00062     // Exception does not work in this case on pre Snow Loopard systems, see JackMachServerNotifyChannel::NotifyQuit()
00063     fThread.Kill();
00064  #else
00065     fThread.Stop();
00066  #endif
00067     fServerPort.DestroyPort();
00068 }
00069     
00070 int JackMachServerChannel::Start()
00071 {
00072     if (fThread.Start() != 0) {
00073         jack_error("Cannot start Jack server listener");
00074         return -1;
00075     }  
00076     
00077     return 0;
00078 }
00079 
00080 JackLockedEngine* JackMachServerChannel::GetEngine()
00081 {
00082     return fServer->GetEngine();
00083 }
00084 
00085 JackServer* JackMachServerChannel::GetServer()
00086 {
00087     return fServer;
00088 }
00089 
00090 void JackMachServerChannel::ClientCheck(char* name, char* name_res, int protocol, int options, int* status, int* result)
00091 {
00092     *result = GetEngine()->ClientCheck(name, name_res, protocol, options, status);
00093 }
00094 
00095 void JackMachServerChannel::ClientOpen(char* name, int pid, mach_port_t* private_port, int* shared_engine, int* shared_client, int* shared_graph, int* result)
00096 {
00097     int refnum = -1;
00098     *result = GetEngine()->ClientExternalOpen(name, pid, &refnum, shared_engine, shared_client, shared_graph);
00099 
00100     if (*result == 0) {
00101         mach_port_t port = fServerPort.AddPort();
00102         if (port != 0) {
00103             fClientTable[port] = refnum;
00104             fPortTable[port] = this;
00105             *private_port = port;
00106         } else {
00107             jack_error("Cannot create private client mach port");
00108             *result = -1;
00109         }
00110     } else {
00111         jack_error("Cannot create new client");
00112     }
00113 }
00114 
00115 void JackMachServerChannel::ClientClose(mach_port_t private_port, int refnum)
00116 {
00117     GetEngine()->ClientExternalClose(refnum);
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 void JackMachServerChannel::ClientKill(mach_port_t private_port)
00128 {
00129     jack_log("JackMachServerChannel::ClientKill");
00130     int refnum = fClientTable[private_port];
00131     assert(refnum > 0);
00132     fServer->ClientKill(refnum);
00133     fClientTable.erase(private_port);
00134 
00135     // Hum, hum....
00136     kern_return_t res;
00137     if ((res = mach_port_destroy(mach_task_self(), private_port)) != KERN_SUCCESS) {
00138         jack_error("server_rpc_jack_client_close mach_port_destroy %s", mach_error_string(res));
00139     }
00140 }
00141 
00142 boolean_t JackMachServerChannel::MessageHandler(mach_msg_header_t* Request, mach_msg_header_t* Reply)
00143 {
00144     if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
00145         jack_log("MACH_NOTIFY_NO_SENDERS %ld", Request->msgh_local_port);
00146         JackMachServerChannel* channel = JackMachServerChannel::fPortTable[Request->msgh_local_port];
00147         assert(channel);
00148         channel->ClientKill(Request->msgh_local_port);
00149     } else {
00150         JackRPCEngine_server(Request, Reply);
00151     }
00152     return true;
00153 }
00154 
00155 bool JackMachServerChannel::Execute()
00156 {
00157     try {
00158         
00159         kern_return_t res;
00160         if ((res = mach_msg_server(MessageHandler, 1024, fServerPort.GetPortSet(), 0)) != KERN_SUCCESS) {
00161             jack_log("JackMachServerChannel::Execute: err = %s", mach_error_string(res));
00162             // A recoverable error, so keep running...
00163         }
00164         return true;
00165         
00166     } catch (JackQuitException& e) {
00167         jack_log("JackMachServerChannel::Execute JackQuitException");
00168         return false;
00169     }
00170 }
00171 
00172 } // end of namespace
00173 
00174