Jack2  1.9.9
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 
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107