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.

419 lines
13KB

  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 JackWinNamedPipeAux::ReadAux(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_log("Cannot read named pipe name = %s err = %ld", fName, GetLastError());
  30. return -1;
  31. }
  32. }
  33. int JackWinNamedPipeAux::WriteAux(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_log("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("JackWinNamedPipeClient::ConnectAux : 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 or ERROR_FILE_NOT_FOUND occurs.
  85. if ((GetLastError() != ERROR_PIPE_BUSY) && (GetLastError() != ERROR_FILE_NOT_FOUND)) {
  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 after wait = %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. /*
  119. COMMTIMEOUTS timeout;
  120. if (GetCommTimeouts(fNamedPipe, &timeout)) {
  121. jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadIntervalTimeout = %d", timeout.ReadIntervalTimeout);
  122. jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutMultiplier = %d", timeout.ReadTotalTimeoutMultiplier);
  123. jack_info("JackWinNamedPipeClient::SetReadTimeOut ReadTotalTimeoutConstant = %d", timeout.ReadTotalTimeoutConstant);
  124. } else {
  125. jack_error("JackWinNamedPipeClient::SetReadTimeOut err %d", GetLastError());
  126. }
  127. */
  128. }
  129. void JackWinNamedPipeClient::SetWriteTimeOut(long sec)
  130. {
  131. /*
  132. COMMTIMEOUTS timeout;
  133. if (GetCommTimeouts(fNamedPipe, &timeout)) {
  134. jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutMultiplier = %d", timeout.WriteTotalTimeoutMultiplier);
  135. jack_info("JackWinNamedPipeClient::SetWriteTimeOut WriteTotalTimeoutConstant = %d", timeout.WriteTotalTimeoutConstant);
  136. }
  137. */
  138. }
  139. JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient()
  140. : JackWinNamedPipeClient(), fPendingIO(false), fIOState(kIdle)
  141. {
  142. fIOState = kIdle;
  143. fOverlap.hEvent = CreateEvent(NULL, // default security attribute
  144. TRUE, // manual-reset event
  145. TRUE, // initial state = signaled
  146. NULL); // unnamed event object
  147. }
  148. JackWinAsyncNamedPipeClient::JackWinAsyncNamedPipeClient(HANDLE pipe, const char* name, bool pending)
  149. : JackWinNamedPipeClient(pipe, name), fPendingIO(pending), fIOState(kIdle)
  150. {
  151. fOverlap.hEvent = CreateEvent(NULL, // default security attribute
  152. TRUE, // manual-reset event
  153. TRUE, // initial state = signaled
  154. NULL); // unnamed event object
  155. if (!fPendingIO) {
  156. SetEvent(fOverlap.hEvent);
  157. }
  158. fIOState = (fPendingIO) ? kConnecting : kReading;
  159. }
  160. JackWinAsyncNamedPipeClient::~JackWinAsyncNamedPipeClient()
  161. {
  162. CloseHandle(fOverlap.hEvent);
  163. }
  164. int JackWinAsyncNamedPipeClient::FinishIO()
  165. {
  166. DWORD success, ret;
  167. success = GetOverlappedResult(fNamedPipe, // handle to pipe
  168. &fOverlap, // OVERLAPPED structure
  169. &ret, // bytes transferred
  170. FALSE); // do not wait
  171. switch (fIOState) {
  172. case kConnecting:
  173. if (!success) {
  174. jack_error("Conection error");
  175. return -1;
  176. } else {
  177. fIOState = kReading;
  178. // Prepare connection for new client ??
  179. }
  180. break;
  181. case kReading:
  182. if (!success || ret == 0) {
  183. return -1;
  184. }
  185. fIOState = kWriting;
  186. break;
  187. case kWriting:
  188. if (!success || ret == 0) {
  189. return -1;
  190. }
  191. fIOState = kReading;
  192. break;
  193. default:
  194. break;
  195. }
  196. return 0;
  197. }
  198. int JackWinAsyncNamedPipeClient::Read(void* data, int len)
  199. {
  200. DWORD read;
  201. jack_log("JackWinNamedPipeClient::Read len = %ld", len);
  202. BOOL res = ReadFile(fNamedPipe, data, len, &read, &fOverlap);
  203. if (res && read != 0) {
  204. fPendingIO = false;
  205. fIOState = kWriting;
  206. return 0;
  207. } else if (!res && GetLastError() == ERROR_IO_PENDING) {
  208. fPendingIO = true;
  209. return 0;
  210. } else {
  211. jack_error("Cannot read named pipe err = %ld", GetLastError());
  212. return -1;
  213. }
  214. }
  215. int JackWinAsyncNamedPipeClient::Write(void* data, int len)
  216. {
  217. DWORD written;
  218. jack_log("JackWinNamedPipeClient::Write len = %ld", len);
  219. BOOL res = WriteFile(fNamedPipe, data, len, &written, &fOverlap);
  220. if (res && written != 0) {
  221. fPendingIO = false;
  222. fIOState = kWriting;
  223. return 0;
  224. } else if (!res && GetLastError() == ERROR_IO_PENDING) {
  225. fPendingIO = true;
  226. return 0;
  227. } else {
  228. jack_error("Cannot write named pipe err = %ld", GetLastError());
  229. return -1;
  230. }
  231. }
  232. // Server side
  233. int JackWinNamedPipeServer::BindAux()
  234. {
  235. jack_log("JackWinNamedPipeServer::BindAux : fName %s", fName);
  236. if ((fNamedPipe = CreateNamedPipe(fName,
  237. PIPE_ACCESS_DUPLEX, // read/write access
  238. PIPE_TYPE_MESSAGE | // message type pipe
  239. PIPE_READMODE_MESSAGE | // message-read mode
  240. PIPE_WAIT, // blocking mode
  241. PIPE_UNLIMITED_INSTANCES, // max. instances
  242. BUFSIZE, // output buffer size
  243. BUFSIZE, // input buffer size
  244. INFINITE, // client time-out
  245. NULL)) == INVALID_HANDLE_VALUE) { // no security
  246. jack_error("Cannot bind server to pipe err = %ld", GetLastError());
  247. return -1;
  248. } else {
  249. return 0;
  250. }
  251. }
  252. int JackWinNamedPipeServer::Bind(const char* dir, int which)
  253. {
  254. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
  255. return BindAux();
  256. }
  257. int JackWinNamedPipeServer::Bind(const char* dir, const char* name, int which)
  258. {
  259. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
  260. return BindAux();
  261. }
  262. bool JackWinNamedPipeServer::Accept()
  263. {
  264. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  265. return true;
  266. } else {
  267. jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
  268. if (GetLastError() == ERROR_PIPE_CONNECTED) {
  269. jack_error("Pipe already connnected = %s", fName);
  270. return true;
  271. } else {
  272. return false;
  273. }
  274. }
  275. }
  276. JackWinNamedPipeClient* JackWinNamedPipeServer::AcceptClient()
  277. {
  278. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  279. JackWinNamedPipeClient* client = new JackWinNamedPipeClient(fNamedPipe, fName);
  280. // Init the pipe to the default value
  281. fNamedPipe = INVALID_HANDLE_VALUE;
  282. return client;
  283. } else {
  284. switch (GetLastError()) {
  285. case ERROR_PIPE_CONNECTED:
  286. return new JackWinNamedPipeClient(fNamedPipe, fName);
  287. default:
  288. jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
  289. return NULL;
  290. }
  291. }
  292. }
  293. int JackWinNamedPipeServer::Close()
  294. {
  295. jack_log("JackWinNamedPipeServer::Close");
  296. if (fNamedPipe != INVALID_HANDLE_VALUE) {
  297. DisconnectNamedPipe(fNamedPipe);
  298. CloseHandle(fNamedPipe);
  299. fNamedPipe = INVALID_HANDLE_VALUE;
  300. return 0;
  301. } else {
  302. return -1;
  303. }
  304. }
  305. // Server side
  306. int JackWinAsyncNamedPipeServer::BindAux()
  307. {
  308. jack_log("JackWinAsyncNamedPipeServer::BindAux : fName %s", fName);
  309. if ((fNamedPipe = CreateNamedPipe(fName,
  310. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
  311. PIPE_TYPE_MESSAGE | // message type pipe
  312. PIPE_READMODE_MESSAGE | // message-read mode
  313. PIPE_WAIT, // blocking mode
  314. PIPE_UNLIMITED_INSTANCES, // max. instances
  315. BUFSIZE, // output buffer size
  316. BUFSIZE, // input buffer size
  317. INFINITE, // client time-out
  318. NULL)) == INVALID_HANDLE_VALUE) { // no security a
  319. jack_error("Cannot bind server to pipe err = %ld", GetLastError());
  320. return -1;
  321. } else {
  322. return 0;
  323. }
  324. }
  325. int JackWinAsyncNamedPipeServer::Bind(const char* dir, int which)
  326. {
  327. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%d", dir, which);
  328. return BindAux();
  329. }
  330. int JackWinAsyncNamedPipeServer::Bind(const char* dir, const char* name, int which)
  331. {
  332. snprintf(fName, sizeof(fName), "\\\\.\\pipe\\%s_jack_%s_%d", dir, name, which);
  333. return BindAux();
  334. }
  335. bool JackWinAsyncNamedPipeServer::Accept()
  336. {
  337. return false;
  338. }
  339. JackWinNamedPipeClient* JackWinAsyncNamedPipeServer::AcceptClient()
  340. {
  341. if (ConnectNamedPipe(fNamedPipe, NULL)) {
  342. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
  343. } else {
  344. switch (GetLastError()) {
  345. case ERROR_IO_PENDING:
  346. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, true);
  347. case ERROR_PIPE_CONNECTED:
  348. return new JackWinAsyncNamedPipeClient(fNamedPipe, fName, false);
  349. default:
  350. jack_error("Cannot connect server pipe name = %s err = %ld", fName, GetLastError());
  351. return NULL;
  352. break;
  353. }
  354. }
  355. }
  356. } // end of namespace