jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
12KB

  1. /*
  2. Copyright (C) 2004-2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "JackWinNamedPipe.h"
  16. #include "JackError.h"
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #define BUFSIZE 4096
  20. namespace Jack
  21. {
  22. int JackWinNamedPipe::Read(void* data, int len)
  23. {
  24. DWORD read;
  25. BOOL res = ReadFile(fNamedPipe, data, len, &read, NULL);
  26. if (res && read == (DWORD)len) {
  27. return 0;
  28. } else {
  29. jack_error("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
  30. return -1;
  31. }
  32. }
  33. int JackWinNamedPipe::Write(void* data, int len)
  34. {
  35. DWORD written;
  36. BOOL res = WriteFile(fNamedPipe, data, len, &written, NULL);
  37. if (res && written == (DWORD)len) {
  38. return 0;
  39. } else {
  40. jack_error("Cannot write named pipe name = %s err = %ld", fName, GetLastError());
  41. return -1;
  42. }
  43. }
  44. /*
  45. See :
  46. http://answers.google.com/answers/threadview?id=430173
  47. http://msdn.microsoft.com/en-us/library/windows/desktop/aa365800(v=vs.85).aspx
  48. */
  49. /*
  50. int JackWinNamedPipeClient::ConnectAux()
  51. {
  52. fNamedPipe = CreateFile(fName, // pipe name
  53. GENERIC_READ | // read and write access
  54. GENERIC_WRITE,
  55. 0, // no sharing
  56. NULL, // default security attributes
  57. OPEN_EXISTING, // opens existing pipe
  58. 0, // default attributes
  59. NULL); // no template file
  60. if (fNamedPipe == INVALID_HANDLE_VALUE) {
  61. jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
  62. return -1;
  63. } else {
  64. return 0;
  65. }
  66. }
  67. */
  68. int JackWinNamedPipeClient::ConnectAux()
  69. {
  70. jack_log("Connect: fName %s", fName);
  71. while (true) {
  72. fNamedPipe = CreateFile(fName, // pipe name
  73. GENERIC_READ | // read and write access
  74. GENERIC_WRITE,
  75. 0, // no sharing
  76. NULL, // default security attributes
  77. OPEN_EXISTING, // opens existing pipe
  78. 0, // default attributes
  79. NULL); // no template file
  80. // Break if the pipe handle is valid.
  81. if (fNamedPipe != INVALID_HANDLE_VALUE) {
  82. return 0;
  83. }
  84. // Exit if an error other than ERROR_PIPE_BUSY occurs.
  85. if (GetLastError() != ERROR_PIPE_BUSY) {
  86. jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
  87. return -1;
  88. }
  89. // All pipe instances are busy, so wait for 2 seconds.
  90. if (!WaitNamedPipe(fName, 2000)) {
  91. jack_error("Cannot connect to named pipe = %s err = %ld", fName, GetLastError());
  92. return -1;
  93. }
  94. }
  95. }
  96. int JackWinNamedPipeClient::Connect(const char* dir, int which)
  97. {
  98. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
  99. return ConnectAux();
  100. }
  101. int JackWinNamedPipeClient::Connect(const char* dir, const char* name, int which)
  102. {
  103. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
  104. return ConnectAux();
  105. }
  106. int JackWinNamedPipeClient::Close()
  107. {
  108. if (fNamedPipe != INVALID_HANDLE_VALUE) {
  109. CloseHandle(fNamedPipe);
  110. fNamedPipe = INVALID_HANDLE_VALUE;
  111. return 0;
  112. } else {
  113. return -1;
  114. }
  115. }
  116. void JackWinNamedPipeClient::SetReadTimeOut(long sec)
  117. {}
  118. void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
  119. {}
  120. JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
  121. : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
  122. {
  123. fIOState = kIdle;
  124. fOverlap.hEvent = CreateEvent(NULL, // default security attribute
  125. TRUE, // manual-reset event
  126. TRUE, // initial state = signaled
  127. NULL); // unnamed event object
  128. }
  129. JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
  130. : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
  131. {
  132. fOverlap.hEvent = CreateEvent(NULL, // default security attribute
  133. TRUE, // manual-reset event
  134. TRUE, // initial state = signaled
  135. NULL); // unnamed event object
  136. if (!fPendingIO) {
  137. SetEvent(fOverlap.hEvent);
  138. }
  139. fIOState = (fPendingIO) ? kConnecting : kReading;
  140. }
  141. JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
  142. {
  143. CloseHandle(fOverlap.hEvent);
  144. }
  145. int JackWinAsyncNamedPipeClient::FinishIO()
  146. {
  147. DWORD success, ret;
  148. success = GetOverlappedResult(fNamedPipe, // handle to pipe
  149. &fOverlap, // OVERLAPPED structure
  150. &ret, // bytes transferred
  151. FALSE); // do not wait
  152. switch (fIOState) {
  153. case kConnecting:
  154. if (!success) {
  155. jack_error("Conection error");
  156. return -1;
  157. } else {
  158. fIOState = kReading;
  159. // Prepare connection for new client ??
  160. }
  161. break;
  162. case kReading:
  163. if (!success || ret == 0) {
  164. return -1;
  165. }
  166. fIOState = kWriting;
  167. break;
  168. case kWriting:
  169. if (!success || ret == 0) {
  170. return -1;
  171. }
  172. fIOState = kReading;
  173. break;
  174. default:
  175. break;
  176. }
  177. return 0;
  178. }
  179. int JackWinAsyncNamedPipeClient::Read(void* data, int len)
  180. {
  181. DWORD read;
  182. jack_log("JackWinNamedPipeClient::Read len = %ld", len);
  183. BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
  184. if (res && read != 0) {
  185. fPendingIO = false;
  186. fIOState = kWriting;
  187. return 0;
  188. } else if (!res && GetLastError() == ERROR_IO_PENDING) {
  189. fPendingIO = true;
  190. return 0;
  191. } else {
  192. jack_error("Cannot read named pipe err = %ld", GetLastError());
  193. return -1;
  194. }
  195. }
  196. int JackWinAsyncNamedPipeClient::Write(void* data, int len)
  197. {
  198. DWORD written;
  199. jack_log("JackWinNamedPipeClient::Write len = %ld", len);
  200. BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
  201. if (res && written != 0) {
  202. fPendingIO = false;
  203. fIOState = kWriting;
  204. return 0;
  205. } else if (!res && GetLastError() == ERROR_IO_PENDING) {
  206. fPendingIO = true;
  207. return 0;
  208. } else {
  209. jack_error("Cannot write named pipe err = %ld", GetLastError());
  210. return -1;
  211. }
  212. }
  213. // Server side
  214. int JackWinNamedPipeServer::BindAux()
  215. {
  216. jack_log("Bind: fName %s", fName);
  217. if ((fNamedPipe = CreateNamedPipe(fName,
  218. PIPE_ACCESS_DUPLEX, // read/write access
  219. PIPE_TYPE_MESSAGE | // message type pipe
  220. PIPE_READMODE_MESSAGE | // message-read mode
  221. PIPE_WAIT, // blocking mode
  222. PIPE_UNLIMITED_INSTANCES, // max. instances
  223. BUFSIZE, // output buffer size
  224. BUFSIZE, // input buffer size
  225. INFINITE, // client time-out
  226. NULL)) == INVALID_HANDLE_VALUE) { // no security
  227. jack_error("Cannot bind server to pipe err = %ld", GetLastError());
  228. return -1;
  229. } else {
  230. return 0;
  231. }
  232. }
  233. int JackWinNamedPipeServer::Bind(const char* dir, int which)
  234. {
  235. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
  236. return BindAux();
  237. }
  238. int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
  239. {
  240. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
  241. return BindAux();
  242. }
  243. bool JackWinNamedPipeServer::Accept()
  244. {
  245. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  246. return true;
  247. } else {
  248. jack_error("Cannot bind server pipe name = %s err = %ld", fName, GetLastError());
  249. if (GetLastError() == ERROR_PIPE_CONNECTED) {
  250. jack_error("pipe already connnected = %s ", fName);
  251. return true;
  252. } else {
  253. return false;
  254. }
  255. }
  256. }
  257. JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
  258. {
  259. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  260. JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
  261. // Init the pipe to the default value
  262. fNamedPipe = INVALID_HANDLE_VALUE;
  263. return client;
  264. } else {
  265. switch (GetLastError()) {
  266. case ERROR_PIPE_CONNECTED:
  267. return new JackWinNamedPipeClient(fNamedPipe, fName);
  268. default:
  269. jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
  270. return NULL;
  271. break;
  272. }
  273. }
  274. }
  275. int JackWinNamedPipeServer::Close()
  276. {
  277. jack_log("JackWinNamedPipeServer::Close");
  278. if (fNamedPipe != INVALID_HANDLE_VALUE) {
  279. DisconnectNamedPipe(fNamedPipe);
  280. CloseHandle(fNamedPipe);
  281. fNamedPipe = INVALID_HANDLE_VALUE;
  282. return 0;
  283. } else {
  284. return -1;
  285. }
  286. }
  287. // Server side
  288. int JackWinAsyncNamedPipeServer::BindAux()
  289. {
  290. jack_log("Bind: fName %s", fName);
  291. if ((fNamedPipe = CreateNamedPipe(fName,
  292. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
  293. PIPE_TYPE_MESSAGE | // message type pipe
  294. PIPE_READMODE_MESSAGE | // message-read mode
  295. PIPE_WAIT, // blocking mode
  296. PIPE_UNLIMITED_INSTANCES, // max. instances
  297. BUFSIZE, // output buffer size
  298. BUFSIZE, // input buffer size
  299. INFINITE, // client time-out
  300. NULL)) == INVALID_HANDLE_VALUE) { // no security a
  301. jack_error("Cannot bind server to pipe err = %ld", GetLastError());
  302. return -1;
  303. } else {
  304. return 0;
  305. }
  306. }
  307. int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
  308. {
  309. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
  310. return BindAux();
  311. }
  312. int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
  313. {
  314. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
  315. return BindAux();
  316. }
  317. bool JackWinAsyncNamedPipeServer::Accept()
  318. {
  319. return false;
  320. }
  321. JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
  322. {
  323. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  324. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
  325. } else {
  326. switch (GetLastError()) {
  327. case ERROR_IO_PENDING:
  328. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
  329. case ERROR_PIPE_CONNECTED:
  330. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
  331. default:
  332. jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
  333. return NULL;
  334. break;
  335. }
  336. }
  337. }
  338. } // end of namespace