Jack2 1.9.12

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->GetEngine()->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
202 bool JackWinNamedPipeServerChannel::Init()
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
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
Jack::JackWinNamedPipeServerChannel::Init
bool Init()
Definition: JackWinNamedPipeServerChannel.cpp:202
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108