Jack2 1.9.12

JackWinNamedPipe.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 "JackWinNamedPipe.h"
22 #include "JackError.h"
23 #include <assert.h>
24 #include <stdio.h>
25
26 #define BUFSIZE 4096
27
28 namespace Jack
29 {
30
31 int JackWinNamedPipeAux::ReadAux(void* data, int len)
32 {
33 DWORD read;
34 BOOL res = ReadFile(fNamedPipe, data, len, &read, NULL);
35 if (res && read == (DWORD)len) {
36 return 0;
37 } else {
38 jack_log("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
39 return -1;
40 }
41 }
42
43 int JackWinNamedPipeAux::WriteAux(void* data, int len)
44 {
45 DWORD written;
46 BOOL res = WriteFile(fNamedPipe, data, len, &written, NULL);
47 if (res && written == (DWORD)len) {
48 return 0;
49 } else {
50 jack_log("Cannot write named pipe name = %s err = %ld", fName, GetLastError());
51 return -1;
52 }
53 }
54
55 /*
56 See :
57 http://answers.google.com/answers/threadview?id=430173
58 http://msdn.microsoft.com/en-us/library/windows/desktop/aa365800(v=vs.85).aspx
59 */
60
61 /*
62 int JackWinNamedPipeClient::ConnectAux()
63 {
64 fNamedPipe = CreateFile(fName, // pipe name
65 GENERIC_READ | // read and write access
66 GENERIC_WRITE,
67 0, // no sharing
68 NULL, // default security attributes
69 OPEN_EXISTING, // opens existing pipe
70 0, // default attributes
71 NULL); // no template file
72
73 if (fNamedPipe == INVALID_HANDLE_VALUE) {
74 jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
75 return -1;
76 } else {
77 return 0;
78 }
79 }
80 */
81
82 int JackWinNamedPipeClient::ConnectAux()
83 {
84 jack_log("JackWinNamedPipeClient::ConnectAux : fName %s", fName);
85
86 while (true) {
87
88 fNamedPipe = CreateFile(fName, // pipe name
89 GENERIC_READ | // read and write access
90 GENERIC_WRITE,
91 0, // no sharing
92 NULL, // default security attributes
93 OPEN_EXISTING, // opens existing pipe
94 0, // default attributes
95 NULL); // no template file
96
97 // Break if the pipe handle is valid.
98 if (fNamedPipe != INVALID_HANDLE_VALUE) {
99 return 0;
100 }
101
102 // Exit if an error other than ERROR_PIPE_BUSY or ERROR_FILE_NOT_FOUND occurs.
103 if ((GetLastError() != ERROR_PIPE_BUSY) && (GetLastError() != ERROR_FILE_NOT_FOUND)) {
104 jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
105 return -1;
106 }
107
108 // All pipe instances are busy, so wait for 2 seconds.
109 if (!WaitNamedPipe(fName, 2000)) {
110 jack_error("Cannot connect to named pipe after wait = %s err = %ld", fName, GetLastError());
111 return -1;
112 }
113 }
114 }
115
116 int JackWinNamedPipeClient::Connect(const char* dir, int which)
117 {
118 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
119 return ConnectAux();
120 }
121
122 int JackWinNamedPipeClient::Connect(const char* dir, const char* name, int which)
123 {
124 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
125 return ConnectAux();
126 }
127
128 int JackWinNamedPipeClient::Close()
129 {
130 if (fNamedPipe != INVALID_HANDLE_VALUE) {
131 CloseHandle(fNamedPipe);
132 fNamedPipe = INVALID_HANDLE_VALUE;
133 return 0;
134 } else {
135 return -1;
136 }
137 }
138
139 void JackWinNamedPipeClient::SetReadTimeOut(long sec)
140 {
141 /*
142 COMMTIMEOUTS timeout;
143 if (GetCommTimeouts(fNamedPipe, &timeout)) {
144 jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadIntervalTimeout = %d", timeout.ReadIntervalTimeout);
145 jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutMultiplier = %d", timeout.ReadTotalTimeoutMultiplier);
146 jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutConstant = %d", timeout.ReadTotalTimeoutConstant);
147 } else {
148 jack_error("JackWinNamedPipeClient::SetReadTimeOut err %d", GetLastError());
149 }
150 */
151 }
152
153 void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
154 {
155 /*
156 COMMTIMEOUTS timeout;
157 if (GetCommTimeouts(fNamedPipe, &timeout)) {
158 jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutMultiplier = %d", timeout.WriteTotalTimeoutMultiplier);
159 jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutConstant = %d", timeout.WriteTotalTimeoutConstant);
160 }
161 */
162 }
163
164 void JackWinNamedPipeClient::SetNonBlocking(bool onoff)
165 {}
166
167 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
168 : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
169 {
170 fIOState = kIdle;
171 fOverlap.hEvent = CreateEvent(NULL, // default security attribute
172 TRUE, // manual-reset event
173 TRUE, // initial state = signaled
174 NULL); // unnamed event object
175 }
176
177 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
178 : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
179 {
180 fOverlap.hEvent = CreateEvent(NULL, // default security attribute
181 TRUE, // manual-reset event
182 TRUE, // initial state = signaled
183 NULL); // unnamed event object
184
185 if (!fPendingIO) {
186 SetEvent(fOverlap.hEvent);
187 }
188
189 fIOState = (fPendingIO) ? kConnecting : kReading;
190 }
191
192 JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
193 {
194 CloseHandle(fOverlap.hEvent);
195 }
196
197 int JackWinAsyncNamedPipeClient::FinishIO()
198 {
199 DWORD success, ret;
200 success = GetOverlappedResult(fNamedPipe, // handle to pipe
201 &fOverlap, // OVERLAPPED structure
202 &ret, // bytes transferred
203 FALSE); // do not wait
204
205 switch (fIOState) {
206
207 case kConnecting:
208 if (!success) {
209 jack_error("Conection error");
210 return -1;
211 } else {
212 fIOState = kReading;
213 // Prepare connection for new client ??
214 }
215 break;
216
217 case kReading:
218 if (!success || ret == 0) {
219 return -1;
220 }
221 fIOState = kWriting;
222 break;
223
224 case kWriting:
225 if (!success || ret == 0) {
226 return -1;
227 }
228 fIOState = kReading;
229 break;
230
231 default:
232 break;
233 }
234
235 return 0;
236 }
237
238 int JackWinAsyncNamedPipeClient::Read(void* data, int len)
239 {
240 DWORD read;
241 jack_log("JackWinNamedPipeClient::Read len = %ld", len);
242 BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
243
244 if (res && read != 0) {
245 fPendingIO = false;
246 fIOState = kWriting;
247 return 0;
248 } else if (!res && GetLastError() == ERROR_IO_PENDING) {
249 fPendingIO = true;
250 return 0;
251 } else {
252 jack_error("Cannot read named pipe err = %ld", GetLastError());
253 return -1;
254 }
255 }
256
257 int JackWinAsyncNamedPipeClient::Write(void* data, int len)
258 {
259 DWORD written;
260 jack_log("JackWinNamedPipeClient::Write len = %ld", len);
261 BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
262
263 if (res && written != 0) {
264 fPendingIO = false;
265 fIOState = kWriting;
266 return 0;
267 } else if (!res && GetLastError() == ERROR_IO_PENDING) {
268 fPendingIO = true;
269 return 0;
270 } else {
271 jack_error("Cannot write named pipe err = %ld", GetLastError());
272 return -1;
273 }
274 }
275
276 // Server side
277 int JackWinNamedPipeServer::BindAux()
278 {
279 jack_log("JackWinNamedPipeServer::BindAux : fName %s", fName);
280
281 if ((fNamedPipe = CreateNamedPipe(fName,
282 PIPE_ACCESS_DUPLEX, // read/write access
283 PIPE_TYPE_MESSAGE | // message type pipe
284 PIPE_READMODE_MESSAGE | // message-read mode
285 PIPE_WAIT, // blocking mode
286 PIPE_UNLIMITED_INSTANCES, // max. instances
287 BUFSIZE, // output buffer size
288 BUFSIZE, // input buffer size
289 INFINITE, // client time-out
290 NULL)) == INVALID_HANDLE_VALUE) { // no security
291 jack_error("Cannot bind server to pipe err = %ld", GetLastError());
292 return -1;
293 } else {
294 return 0;
295 }
296 }
297
298 int JackWinNamedPipeServer::Bind(const char* dir, int which)
299 {
300 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
301 return BindAux();
302 }
303
304 int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
305 {
306 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
307 return BindAux();
308 }
309
310 bool JackWinNamedPipeServer::Accept()
311 {
312 if (ConnectNamedPipe(fNamedPipe, NULL)) {
313 return true;
314 } else {
315 jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
316 if (GetLastError() == ERROR_PIPE_CONNECTED) {
317 jack_error("Pipe already connnected = %s", fName);
318 return true;
319 } else {
320 return false;
321 }
322 }
323 }
324
325 JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
326 {
327 if (ConnectNamedPipe(fNamedPipe, NULL)) {
328 JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
329 // Init the pipe to the default value
330 fNamedPipe = INVALID_HANDLE_VALUE;
331 return client;
332 } else {
333 switch (GetLastError()) {
334
335 case ERROR_PIPE_CONNECTED:
336 return new JackWinNamedPipeClient(fNamedPipe, fName);
337
338 default:
339 jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
340 return NULL;
341 }
342 }
343 }
344
345 int JackWinNamedPipeServer::Close()
346 {
347 jack_log("JackWinNamedPipeServer::Close");
348
349 if (fNamedPipe != INVALID_HANDLE_VALUE) {
350 DisconnectNamedPipe(fNamedPipe);
351 CloseHandle(fNamedPipe);
352 fNamedPipe = INVALID_HANDLE_VALUE;
353 return 0;
354 } else {
355 return -1;
356 }
357 }
358
359 // Server side
360
361 int JackWinAsyncNamedPipeServer::BindAux()
362 {
363 jack_log("JackWinAsyncNamedPipeServer::BindAux : fName %s", fName);
364
365 if ((fNamedPipe = CreateNamedPipe(fName,
366 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
367 PIPE_TYPE_MESSAGE | // message type pipe
368 PIPE_READMODE_MESSAGE | // message-read mode
369 PIPE_WAIT, // blocking mode
370 PIPE_UNLIMITED_INSTANCES, // max. instances
371 BUFSIZE, // output buffer size
372 BUFSIZE, // input buffer size
373 INFINITE, // client time-out
374 NULL)) == INVALID_HANDLE_VALUE) { // no security a
375 jack_error("Cannot bind server to pipe err = %ld", GetLastError());
376 return -1;
377 } else {
378 return 0;
379 }
380 }
381
382 int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
383 {
384 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
385 return BindAux();
386 }
387
388 int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
389 {
390 snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
391 return BindAux();
392 }
393
394 bool JackWinAsyncNamedPipeServer::Accept()
395 {
396 return false;
397 }
398
399 JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
400 {
401 if (ConnectNamedPipe(fNamedPipe, NULL)) {
402 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
403 } else {
404 switch (GetLastError()) {
405
406 case ERROR_IO_PENDING:
407 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
408
409 case ERROR_PIPE_CONNECTED:
410 return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
411
412 default:
413 jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
414 return NULL;
415 break;
416 }
417 }
418 }
419
420 } // end of namespace
421
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108