Jack2  1.9.8
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 JackWinNamedPipe::Read(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_error("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
39  return -1;
40  }
41 }
42 
43 int JackWinNamedPipe::Write(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_error("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("Connect: 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 occurs.
103  if (GetLastError() != ERROR_PIPE_BUSY) {
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 = %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 void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
143 {}
144 
145 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
146  : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
147 {
148  fIOState = kIdle;
149  fOverlap.hEvent = CreateEvent(NULL, // default security attribute
150  TRUE, // manual-reset event
151  TRUE, // initial state = signaled
152  NULL); // unnamed event object
153 }
154 
155 JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
156  : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
157 {
158  fOverlap.hEvent = CreateEvent(NULL, // default security attribute
159  TRUE, // manual-reset event
160  TRUE, // initial state = signaled
161  NULL); // unnamed event object
162 
163  if (!fPendingIO) {
164  SetEvent(fOverlap.hEvent);
165  }
166 
167  fIOState = (fPendingIO) ? kConnecting : kReading;
168 }
169 
170 JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
171 {
172  CloseHandle(fOverlap.hEvent);
173 }
174 
175 int JackWinAsyncNamedPipeClient::FinishIO()
176 {
177  DWORD success, ret;
178  success = GetOverlappedResult(fNamedPipe, // handle to pipe
179  &fOverlap, // OVERLAPPED structure
180  &ret, // bytes transferred
181  FALSE); // do not wait
182 
183  switch (fIOState) {
184 
185  case kConnecting:
186  if (!success) {
187  jack_error("Conection error");
188  return -1;
189  } else {
190  fIOState = kReading;
191  // Prepare connection for new client ??
192  }
193  break;
194 
195  case kReading:
196  if (!success || ret == 0) {
197  return -1;
198  }
199  fIOState = kWriting;
200  break;
201 
202  case kWriting:
203  if (!success || ret == 0) {
204  return -1;
205  }
206  fIOState = kReading;
207  break;
208 
209  default:
210  break;
211  }
212 
213  return 0;
214 }
215 
216 int JackWinAsyncNamedPipeClient::Read(void* data, int len)
217 {
218  DWORD read;
219  jack_log("JackWinNamedPipeClient::Read len = %ld", len);
220  BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
221 
222  if (res && read != 0) {
223  fPendingIO = false;
224  fIOState = kWriting;
225  return 0;
226  } else if (!res && GetLastError() == ERROR_IO_PENDING) {
227  fPendingIO = true;
228  return 0;
229  } else {
230  jack_error("Cannot read named pipe err = %ld", GetLastError());
231  return -1;
232  }
233 }
234 
235 int JackWinAsyncNamedPipeClient::Write(void* data, int len)
236 {
237  DWORD written;
238  jack_log("JackWinNamedPipeClient::Write len = %ld", len);
239  BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
240 
241  if (res && written != 0) {
242  fPendingIO = false;
243  fIOState = kWriting;
244  return 0;
245  } else if (!res && GetLastError() == ERROR_IO_PENDING) {
246  fPendingIO = true;
247  return 0;
248  } else {
249  jack_error("Cannot write named pipe err = %ld", GetLastError());
250  return -1;
251  }
252 }
253 
254 // Server side
255 int JackWinNamedPipeServer::BindAux()
256 {
257  jack_log("Bind: fName %s", fName);
258 
259  if ((fNamedPipe = CreateNamedPipe(fName,
260  PIPE_ACCESS_DUPLEX, // read/write access
261  PIPE_TYPE_MESSAGE | // message type pipe
262  PIPE_READMODE_MESSAGE | // message-read mode
263  PIPE_WAIT, // blocking mode
264  PIPE_UNLIMITED_INSTANCES, // max. instances
265  BUFSIZE, // output buffer size
266  BUFSIZE, // input buffer size
267  INFINITE, // client time-out
268  NULL)) == INVALID_HANDLE_VALUE) { // no security
269  jack_error("Cannot bind server to pipe err = %ld", GetLastError());
270  return -1;
271  } else {
272  return 0;
273  }
274 }
275 
276 int JackWinNamedPipeServer::Bind(const char* dir, int which)
277 {
278  snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
279  return BindAux();
280 }
281 
282 int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
283 {
284  snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
285  return BindAux();
286 }
287 
288 bool JackWinNamedPipeServer::Accept()
289 {
290  if (ConnectNamedPipe(fNamedPipe, NULL)) {
291  return true;
292  } else {
293  jack_error("Cannot bind server pipe name = %s err = %ld", fName, GetLastError());
294  if (GetLastError() == ERROR_PIPE_CONNECTED) {
295  jack_error("pipe already connnected = %s ", fName);
296  return true;
297  } else {
298  return false;
299  }
300  }
301 }
302 
303 JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
304 {
305  if (ConnectNamedPipe(fNamedPipe, NULL)) {
306  JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
307  // Init the pipe to the default value
308  fNamedPipe = INVALID_HANDLE_VALUE;
309  return client;
310  } else {
311  switch (GetLastError()) {
312 
313  case ERROR_PIPE_CONNECTED:
314  return new JackWinNamedPipeClient(fNamedPipe, fName);
315 
316  default:
317  jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
318  return NULL;
319  break;
320  }
321  }
322 }
323 
324 int JackWinNamedPipeServer::Close()
325 {
326  jack_log("JackWinNamedPipeServer::Close");
327 
328  if (fNamedPipe != INVALID_HANDLE_VALUE) {
329  DisconnectNamedPipe(fNamedPipe);
330  CloseHandle(fNamedPipe);
331  fNamedPipe = INVALID_HANDLE_VALUE;
332  return 0;
333  } else {
334  return -1;
335  }
336 }
337 
338 // Server side
339 
340 int JackWinAsyncNamedPipeServer::BindAux()
341 {
342  jack_log("Bind: fName %s", fName);
343 
344  if ((fNamedPipe = CreateNamedPipe(fName,
345  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
346  PIPE_TYPE_MESSAGE | // message type pipe
347  PIPE_READMODE_MESSAGE | // message-read mode
348  PIPE_WAIT, // blocking mode
349  PIPE_UNLIMITED_INSTANCES, // max. instances
350  BUFSIZE, // output buffer size
351  BUFSIZE, // input buffer size
352  INFINITE, // client time-out
353  NULL)) == INVALID_HANDLE_VALUE) { // no security a
354  jack_error("Cannot bind server to pipe err = %ld", GetLastError());
355  return -1;
356  } else {
357  return 0;
358  }
359 }
360 
361 int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
362 {
363  snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
364  return BindAux();
365 }
366 
367 int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
368 {
369  snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
370  return BindAux();
371 }
372 
373 bool JackWinAsyncNamedPipeServer::Accept()
374 {
375  return false;
376 }
377 
378 JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
379 {
380  if (ConnectNamedPipe(fNamedPipe, NULL)) {
381  return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
382  } else {
383  switch (GetLastError()) {
384 
385  case ERROR_IO_PENDING:
386  return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
387 
388  case ERROR_PIPE_CONNECTED:
389  return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
390 
391  default:
392  jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
393  return NULL;
394  break;
395  }
396  }
397 }
398 
399 } // end of namespace
400