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.

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