Jack2  1.9.9
JackWinNamedPipeServerChannel.cpp
1 /*
2  Copyright (C) 2004-2008 Grame
3 
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.
8 
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.
13 
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.
17 
18  */
19 
20 
21 #include "JackWinNamedPipeServerChannel.h"
22 #include "JackNotification.h"
23 #include "JackRequest.h"
24 #include "JackServer.h"
25 #include "JackLockedEngine.h"
26 #include "JackGlobals.h"
27 #include "JackClient.h"
28 #include "JackNotification.h"
29 #include "JackException.h"
30 #include <assert.h>
31 
32 using namespace std;
33 
34 namespace Jack
35 {
36 
37 HANDLE JackClientPipeThread::fMutex = NULL; // Never released....
38 
39 // fRefNum = -1 correspond to already removed client
40 
41 JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient* pipe)
42  :fPipe(pipe), fDecoder(NULL), fServer(NULL), fThread(this), fRefNum(0)
43 {
44  // First one allocated the static fMutex
45  if (fMutex == NULL) {
46  fMutex = CreateMutex(NULL, FALSE, NULL);
47  }
48 }
49 
50 JackClientPipeThread::~JackClientPipeThread()
51 {
52  jack_log("JackClientPipeThread::~JackClientPipeThread");
53  delete fPipe;
54 }
55 
56 int JackClientPipeThread::Open(JackServer* server) // Open the Server/Client connection
57 {
58  // Start listening
59  if (fThread.Start() != 0) {
60  jack_error("Cannot start Jack server listener\n");
61  return -1;
62  } else {
63  fDecoder = new JackRequestDecoder(server, this);
64  fServer = server;
65  return 0;
66  }
67 }
68 
69 void JackClientPipeThread::Close() // Close the Server/Client connection
70 {
71  jack_log("JackClientPipeThread::Close 0 %x %ld", this, fRefNum);
72 
73  //fThread.Kill();
74  fPipe->Close();
75  fRefNum = -1;
76 
77  delete fDecoder;
78  fDecoder = NULL;
79 }
80 
81 bool JackClientPipeThread::Execute()
82 {
83  try {
84 
85  jack_log("JackClientPipeThread::Execute %x", this);
86  JackRequest header;
87  int res = header.Read(fPipe);
88  bool ret = true;
89 
90  // Lock the global mutex
91  if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED) {
92  jack_error("JackClientPipeThread::Execute : mutex wait error");
93  }
94 
95  // Decode header
96  if (res < 0) {
97  jack_log("JackClientPipeThread::Execute : cannot decode header");
98  ClientKill();
99  ret = false;
100  // Decode request
101  } else if (fDecoder->HandleRequest(fPipe, header.fType) < 0) {
102  ret = false;
103  }
104 
105  // Unlock the global mutex
106  if (!ReleaseMutex(fMutex)) {
107  jack_error("JackClientPipeThread::Execute : mutex release error");
108  }
109  return ret;
110 
111  } catch (JackQuitException& e) {
112  jack_log("JackClientPipeThread::Execute : JackQuitException");
113  return false;
114  }
115 }
116 
117 void JackClientPipeThread::ClientAdd(detail::JackChannelTransactionInterface* socket, JackClientOpenRequest* req, JackClientOpenResult *res)
118 {
119  jack_log("JackClientPipeThread::ClientAdd %x %s", this, req->fName);
120  fRefNum = -1;
121  res->fResult = fServer->GetEngine()->ClientExternalOpen(req->fName, req->fPID, req->fUUID, &fRefNum, &res->fSharedEngine, &res->fSharedClient, &res->fSharedGraph);
122 }
123 
124 void JackClientPipeThread::ClientRemove(detail::JackChannelTransactionInterface* socket_aux, int refnum)
125 {
126  jack_log("JackClientPipeThread::ClientRemove ref = %d", refnum);
127  Close();
128 }
129 
130 void JackClientPipeThread::ClientKill()
131 {
132  jack_log("JackClientPipeThread::ClientKill ref = %d", fRefNum);
133 
134  if (fRefNum == -1) { // Correspond to an already removed client.
135  jack_log("Kill a closed client %x", this);
136  } else if (fRefNum == 0) { // Correspond to a still not opened client.
137  jack_log("Kill a not opened client %x", this);
138  } else {
139  fServer->ClientKill(fRefNum);
140  }
141 
142  Close();
143 }
144 
145 JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel():fThread(this)
146 {}
147 
148 JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel()
149 {
150  std::list<JackClientPipeThread*>::iterator it;
151 
152  for (it = fClientList.begin(); it != fClientList.end(); it++) {
153  JackClientPipeThread* client = *it;
154  client->Close();
155  delete client;
156  }
157 }
158 
159 int JackWinNamedPipeServerChannel::Open(const char* server_name, JackServer* server)
160 {
161  jack_log("JackWinNamedPipeServerChannel::Open");
162  snprintf(fServerName, sizeof(fServerName), server_name);
163 
164  // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object
165  if (ClientListen()) {
166  fServer = server;
167  return 0;
168  } else {
169  jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
170  return -1;
171  }
172 }
173 
174 void JackWinNamedPipeServerChannel::Close()
175 {
176  /* TODO : solve WIN32 thread Kill issue
177  This would hang the server... since we are quitting it, its not really problematic,
178  all ressources will be deallocated at the end.
179 
180  fRequestListenPipe.Close();
181  fThread.Stop();
182  */
183 
184  fRequestListenPipe.Close();
185 }
186 
187 int JackWinNamedPipeServerChannel::Start()
188 {
189  if (fThread.Start() != 0) {
190  jack_error("Cannot start Jack server listener");
191  return -1;
192  } else {
193  return 0;
194  }
195 }
196 
197 void JackWinNamedPipeServerChannel::Stop()
198 {
199  fThread.Kill();
200 }
201 
203 {
204  jack_log("JackWinNamedPipeServerChannel::Init");
205  // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object
206  return ClientAccept();
207 }
208 
209 bool JackWinNamedPipeServerChannel::ClientListen()
210 {
211  if (fRequestListenPipe.Bind(jack_server_dir, fServerName, 0) < 0) {
212  jack_error("JackWinNamedPipeServerChannel::ClientListen : cannot create result listen pipe");
213  return false;
214  } else {
215  return true;
216  }
217 }
218 
219 bool JackWinNamedPipeServerChannel::ClientAccept()
220 {
221  JackWinNamedPipeClient* pipe;
222 
223  if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
224  jack_error("JackWinNamedPipeServerChannel::ClientAccept : cannot connect pipe");
225  return false;
226  } else {
227  ClientAdd(pipe);
228  return true;
229  }
230 }
231 
232 bool JackWinNamedPipeServerChannel::Execute()
233 {
234  if (!ClientListen()) {
235  return false;
236  }
237 
238  return ClientAccept();
239 }
240 
241 void JackWinNamedPipeServerChannel::ClientAdd(JackWinNamedPipeClient* pipe)
242 {
243  // Remove dead (= not running anymore) clients.
244  std::list<JackClientPipeThread*>::iterator it = fClientList.begin();
245  JackClientPipeThread* client;
246 
247  jack_log("JackWinNamedPipeServerChannel::ClientAdd size %ld", fClientList.size());
248 
249  while (it != fClientList.end()) {
250  client = *it;
251  if (client->IsRunning()) {
252  it++;
253  } else {
254  it = fClientList.erase(it);
255  delete client;
256  }
257  }
258 
259  client = new JackClientPipeThread(pipe);
260  client->Open(fServer);
261 
262  // Here we are sure that the client is running (because it's thread is in "running" state).
263  fClientList.push_back(client);
264 }
265 
266 } // end of namespace
267 
268 
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107