Leaked source code of windows server 2003
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.

611 lines
15 KiB

  1. // NamedPipe.cpp
  2. #include "precomp.h"
  3. #include "NamedPipe.h"
  4. #include "NCDefs.h"
  5. #include "DUtils.h"
  6. #include "Connection.h"
  7. CNamedPipeClient::CNamedPipeClient() :
  8. m_hPipe(INVALID_HANDLE_VALUE),
  9. m_hthreadReady(NULL),
  10. m_heventProviderReady(NULL),
  11. m_heventDone(NULL),
  12. m_heventCallbackReady(NULL),
  13. m_hthreadCallbackListen(NULL),
  14. m_bDone(FALSE)
  15. {
  16. }
  17. CNamedPipeClient::~CNamedPipeClient()
  18. {
  19. }
  20. CNamedPipeClient::IsReady()
  21. {
  22. return m_hPipe != INVALID_HANDLE_VALUE;
  23. }
  24. BOOL CNamedPipeClient::SendData(LPBYTE pBuffer, DWORD dwSize)
  25. {
  26. BOOL bWritten;
  27. DWORD dwWritten;
  28. #ifdef NO_SEND
  29. bWriten = TRUE;
  30. #else
  31. bWritten =
  32. WriteFile(
  33. m_hPipe,
  34. pBuffer,
  35. dwSize,
  36. &dwWritten,
  37. NULL);
  38. if (!bWritten)
  39. {
  40. TRACE("%d: WriteFile failed, err = %d", GetCurrentProcessId(), GetLastError());
  41. DeinitPipe();
  42. // Start watching for our provider to be ready, and get the pipe.
  43. StartReadyThreadProc();
  44. }
  45. #endif
  46. return bWritten;
  47. }
  48. void CNamedPipeClient::Deinit()
  49. {
  50. HANDLE hthreadReady,
  51. hthreadCallbackListen;
  52. // Protect m_bDone, m_hthreadReady, m_hthreadCallbackListen.
  53. {
  54. CInCritSec cs(&m_cs);
  55. hthreadReady = m_hthreadReady;
  56. hthreadCallbackListen = m_hthreadCallbackListen;
  57. m_hthreadReady = NULL;
  58. m_hthreadCallbackListen = NULL;
  59. m_bDone = TRUE;
  60. }
  61. // Tells both the ready and the callback listen threads to go away.
  62. SetEvent(m_heventDone);
  63. if (hthreadReady)
  64. {
  65. WaitForSingleObject(hthreadReady, INFINITE);
  66. CloseHandle(hthreadReady);
  67. }
  68. if (hthreadCallbackListen)
  69. {
  70. WaitForSingleObject(hthreadCallbackListen, INFINITE);
  71. CloseHandle(hthreadCallbackListen);
  72. }
  73. DeinitPipe();
  74. CloseHandle(m_heventDone);
  75. delete this;
  76. }
  77. // Init function.
  78. BOOL CNamedPipeClient::Init(LPCWSTR szBaseNamespace, LPCWSTR szBaseProvider)
  79. {
  80. //HANDLE heventProviderReady;
  81. // Get the ready event.
  82. StringCchPrintfW(
  83. m_szProviderReadyEvent,
  84. MAX_PATH,
  85. OBJNAME_EVENT_READY L"%s%s",
  86. szBaseNamespace,
  87. szBaseProvider);
  88. // Construct the pipe name.
  89. StringCchPrintfW(
  90. m_szPipeName,
  91. MAX_PATH,
  92. L"\\\\.\\pipe\\" OBJNAME_NAMED_PIPE L"%s%s",
  93. szBaseNamespace,
  94. szBaseProvider);
  95. m_heventDone =
  96. CreateEvent(NULL, TRUE, FALSE, NULL);
  97. if(m_heventDone == NULL)
  98. return FALSE;
  99. // Before we start the thread see if our provider is ready right off
  100. // the bat.
  101. if (!GetPipe())
  102. return StartReadyThreadProc();
  103. return TRUE;
  104. }
  105. BOOL CNamedPipeClient::SignalProviderDisabled()
  106. {
  107. if (m_hPipe != INVALID_HANDLE_VALUE)
  108. {
  109. m_pConnection->IndicateProvDisabled();
  110. DeinitPipe();
  111. if(!StartReadyThreadProc())
  112. return FALSE;
  113. }
  114. return TRUE;
  115. }
  116. BOOL CNamedPipeClient::StartReadyThreadProc()
  117. {
  118. DWORD dwID;
  119. // Protect m_bDone and m_hthreadReady.
  120. CInCritSec cs(&m_cs);
  121. // No need if we're already cleaning up.
  122. if (m_bDone)
  123. return TRUE;
  124. if (m_hthreadReady)
  125. CloseHandle(m_hthreadReady);
  126. m_hthreadReady =
  127. CreateThread(
  128. NULL,
  129. 0,
  130. (LPTHREAD_START_ROUTINE) ProviderReadyThreadProc,
  131. this,
  132. 0,
  133. &dwID);
  134. if(m_hthreadReady == NULL)
  135. return FALSE;
  136. return TRUE;
  137. }
  138. void CNamedPipeClient::DeinitPipe()
  139. {
  140. CInCritSec cs(&m_cs);
  141. // Close the pipe.
  142. if (m_hPipe != INVALID_HANDLE_VALUE)
  143. {
  144. CloseHandle(m_hPipe);
  145. m_hPipe = INVALID_HANDLE_VALUE;
  146. }
  147. }
  148. BOOL CNamedPipeClient::GetPipe()
  149. {
  150. // This block must be protected to keep other threads
  151. // from also trying to get the pipe.
  152. TRACE("Attempting to get event pipe...");
  153. CInCritSec cs(&m_cs);
  154. SetLastError(0);
  155. #define MAX_RETRIES 10
  156. if (m_hPipe == INVALID_HANDLE_VALUE)
  157. {
  158. // Get the pipe
  159. for (int i = 0; i < MAX_RETRIES; i++)
  160. {
  161. m_hPipe =
  162. CreateFileW(
  163. m_szPipeName,
  164. GENERIC_READ | GENERIC_WRITE,
  165. 0,
  166. NULL,
  167. OPEN_EXISTING,
  168. FILE_FLAG_OVERLAPPED | SECURITY_IDENTIFICATION |
  169. SECURITY_SQOS_PRESENT,
  170. NULL);
  171. if ( m_hPipe != INVALID_HANDLE_VALUE )
  172. {
  173. //
  174. // we want to handle Reads using message mode.
  175. //
  176. DWORD dwMode = PIPE_READMODE_MESSAGE;
  177. if ( SetNamedPipeHandleState( m_hPipe, &dwMode, NULL, NULL ) )
  178. {
  179. break;
  180. }
  181. else
  182. {
  183. TRACE("SetNamedPipeHandleState() Failed.");
  184. }
  185. }
  186. else if (GetLastError() == ERROR_PIPE_BUSY)
  187. {
  188. TRACE("Pipe is busy, we'll try again.");
  189. // Try again to get a pipe instance if the pipe is currently busy.
  190. Sleep(100);
  191. continue;
  192. }
  193. }
  194. if (m_hPipe != INVALID_HANDLE_VALUE)
  195. {
  196. TRACE("Got the pipe, calling IncEnabledCount.");
  197. if(!m_pConnection->IndicateProvEnabled())
  198. return FALSE;
  199. }
  200. else
  201. TRACE("Failed to get send pipe.");
  202. }
  203. else
  204. TRACE("Already have a valid pipe.");
  205. return m_hPipe != INVALID_HANDLE_VALUE;
  206. }
  207. DWORD WINAPI CNamedPipeClient::ProviderReadyThreadProc(CNamedPipeClient *pThis)
  208. {
  209. try
  210. {
  211. HANDLE hwaitReady[2];
  212. hwaitReady[0] = pThis->m_heventDone;
  213. // Create the provider ready event.
  214. hwaitReady[1] =
  215. OpenEventW(
  216. SYNCHRONIZE,
  217. FALSE,
  218. pThis->m_szProviderReadyEvent);
  219. if (!hwaitReady[1])
  220. {
  221. PSECURITY_DESCRIPTOR pSD = NULL;
  222. DWORD dwSize;
  223. if ( !ConvertStringSecurityDescriptorToSecurityDescriptorW(
  224. ESS_EVENT_SDDL, // security descriptor string
  225. SDDL_REVISION_1, // revision level
  226. &pSD, // SD
  227. &dwSize) )
  228. return GetLastError();
  229. SECURITY_ATTRIBUTES sa = { sizeof(sa), pSD, FALSE };
  230. hwaitReady[1] =
  231. CreateEventW(
  232. &sa,
  233. TRUE,
  234. FALSE,
  235. pThis->m_szProviderReadyEvent);
  236. DWORD dwErr = GetLastError();
  237. if (pSD)
  238. LocalFree((HLOCAL) pSD);
  239. if (!hwaitReady[1])
  240. {
  241. TRACE("Couldn't create provider ready event: %d", dwErr);
  242. return dwErr;
  243. }
  244. }
  245. TRACE("(Pipe) Waiting for provider ready event.");
  246. while (WaitForMultipleObjects(2, hwaitReady, FALSE, INFINITE) == 1 &&
  247. !pThis->GetPipe())
  248. {
  249. // TODO: Should we close the ready event and then reopen it after we
  250. // sleep?
  251. Sleep(100);
  252. }
  253. // Close the provider ready event.
  254. CloseHandle(hwaitReady[1]);
  255. }
  256. catch( CX_MemoryException )
  257. {
  258. return ERROR_OUTOFMEMORY;
  259. }
  260. return ERROR_SUCCESS;
  261. }
  262. BOOL CNamedPipeClient::InitCallback()
  263. {
  264. if (!m_heventCallbackReady)
  265. {
  266. m_heventCallbackReady = CreateEvent(NULL, FALSE, FALSE, NULL);
  267. if(m_heventCallbackReady == NULL)
  268. return FALSE;
  269. }
  270. if(!StartCallbackListenThread())
  271. return FALSE;
  272. return TRUE;
  273. }
  274. #define PIPE_SIZE 64000
  275. #define CONNECTING_STATE 0
  276. #define READING_STATE 1
  277. #define WRITING_STATE 2
  278. void CNamedPipeClient::SendMsgReply(NC_SRVMSG_REPLY *pReply)
  279. {
  280. if (pReply)
  281. SendData((LPBYTE) pReply, sizeof(*pReply));
  282. }
  283. DWORD WINAPI CNamedPipeClient::CallbackListenThreadProc(CNamedPipeClient *pThis)
  284. {
  285. try
  286. {
  287. READ_DATA dataRead;
  288. HANDLE heventPipeDied = CreateEvent(NULL, TRUE, FALSE, NULL),
  289. hWait[2] = { pThis->m_heventDone, heventPipeDied };
  290. ZeroMemory(&dataRead.overlap, sizeof(dataRead.overlap));
  291. // Since ReadFileEx doesn't use the hEvent, we'll use it to signal this proc
  292. // that something went wrong with the pipe and should try to reconnect.
  293. dataRead.overlap.hEvent = heventPipeDied;
  294. dataRead.pThis = pThis;
  295. // Our callback is ready, so indicate that it's so.
  296. SetEvent(pThis->m_heventCallbackReady);
  297. BOOL bRet;
  298. bRet =
  299. ReadFileEx(
  300. pThis->m_hPipe,
  301. dataRead.cBuffer,
  302. sizeof(dataRead.cBuffer),
  303. (OVERLAPPED*) &dataRead,
  304. (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
  305. if (bRet)
  306. {
  307. DWORD dwRet;
  308. while ((dwRet = WaitForMultipleObjectsEx(2, hWait, FALSE, INFINITE, TRUE))
  309. == WAIT_IO_COMPLETION)
  310. {
  311. }
  312. CloseHandle(heventPipeDied);
  313. // Note: If dwRet == 0, our done event fired and it's time to get out.
  314. // If we got the event that says our pipe went bad, tell our provider that
  315. // it's now disabled.
  316. if (dwRet == 1)
  317. pThis->SignalProviderDisabled();
  318. }
  319. else
  320. pThis->SignalProviderDisabled();
  321. }
  322. catch( CX_MemoryException )
  323. {
  324. return ERROR_OUTOFMEMORY;
  325. }
  326. return ERROR_SUCCESS;
  327. }
  328. void WINAPI CNamedPipeClient::CompletedReadRoutine(
  329. DWORD dwErr,
  330. DWORD nBytesRead,
  331. LPOVERLAPPED pOverlap)
  332. {
  333. READ_DATA *pData = (READ_DATA*) pOverlap;
  334. CNamedPipeClient *pThis = pData->pThis;
  335. BOOL bClosePipe = FALSE;
  336. if(dwErr == 0)
  337. {
  338. if (nBytesRead)
  339. {
  340. pThis->DealWithBuffer(pData, nBytesRead, &bClosePipe);
  341. }
  342. if(!bClosePipe)
  343. {
  344. bClosePipe = !ReadFileEx(
  345. pThis->m_hPipe,
  346. pData->cBuffer,
  347. sizeof(pData->cBuffer),
  348. (OVERLAPPED*) pData,
  349. (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
  350. }
  351. }
  352. else
  353. {
  354. bClosePipe = TRUE;
  355. }
  356. if(bClosePipe)
  357. {
  358. // Close the event to tell our read loop to go away.
  359. SetEvent(pData->overlap.hEvent);
  360. }
  361. }
  362. long CNamedPipeClient::DealWithBuffer( READ_DATA* pData,
  363. DWORD dwOrigBytesRead,
  364. BOOL* pbClosePipe)
  365. {
  366. //
  367. // Check if the actual message is longer that the buffer
  368. //
  369. DWORD dwMessageLength = *(DWORD*)pData->cBuffer;
  370. *pbClosePipe = FALSE;
  371. BOOL bDeleteBuffer = FALSE;
  372. if(dwMessageLength != dwOrigBytesRead)
  373. {
  374. if ( dwMessageLength < dwOrigBytesRead )
  375. {
  376. _ASSERT( FALSE );
  377. return ERROR_INVALID_DATA;
  378. }
  379. //
  380. // Have to read the rest of it --- the message was larger than the
  381. // buffer
  382. //
  383. _ASSERT( dwMessageLength > dwOrigBytesRead );
  384. if ( dwMessageLength >= MAX_MSG_SIZE )
  385. {
  386. return ERROR_NOT_ENOUGH_MEMORY;
  387. }
  388. BYTE* pNewBuffer = new BYTE[dwMessageLength - sizeof(DWORD)];
  389. if(pNewBuffer == NULL)
  390. return ERROR_OUTOFMEMORY;
  391. memcpy(pNewBuffer, pData->cBuffer + sizeof(DWORD),
  392. dwOrigBytesRead - sizeof(DWORD));
  393. OVERLAPPED ov;
  394. memset(&ov, 0, sizeof ov);
  395. ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  396. if(ov.hEvent == NULL)
  397. {
  398. delete [] pNewBuffer;
  399. return GetLastError();
  400. }
  401. DWORD dwExtraBytesRead = 0;
  402. BOOL bSuccess = ReadFile(m_hPipe,
  403. pNewBuffer + dwOrigBytesRead - sizeof(DWORD),
  404. dwMessageLength - dwOrigBytesRead,
  405. &dwExtraBytesRead,
  406. &ov);
  407. CloseHandle(ov.hEvent);
  408. if(!bSuccess)
  409. {
  410. long lRes = GetLastError();
  411. if(lRes == ERROR_IO_PENDING)
  412. {
  413. //
  414. // Fine, I can wait, I got nowhere else to go
  415. //
  416. if(!GetOverlappedResult(m_hPipe,
  417. &ov, &dwExtraBytesRead, TRUE))
  418. {
  419. *pbClosePipe = TRUE;
  420. delete [] pNewBuffer;
  421. return GetLastError();
  422. }
  423. }
  424. else
  425. {
  426. *pbClosePipe = TRUE;
  427. delete [] pNewBuffer;
  428. return lRes;
  429. }
  430. }
  431. if(dwExtraBytesRead != dwMessageLength - dwOrigBytesRead)
  432. {
  433. *pbClosePipe = TRUE;
  434. delete [] pNewBuffer;
  435. return ERROR_OUTOFMEMORY;
  436. }
  437. //
  438. // Process it
  439. //
  440. try
  441. {
  442. m_pConnection->ProcessMessage(pNewBuffer,
  443. dwMessageLength - sizeof(DWORD));
  444. }
  445. catch(...)
  446. {
  447. *pbClosePipe = FALSE;
  448. delete [] pNewBuffer;
  449. return ERROR_OUTOFMEMORY;
  450. }
  451. delete [] pNewBuffer;
  452. }
  453. else
  454. {
  455. //
  456. // All here --- just process it
  457. //
  458. try
  459. {
  460. m_pConnection->ProcessMessage(pData->cBuffer + sizeof(DWORD),
  461. dwMessageLength - sizeof(DWORD));
  462. }
  463. catch(...)
  464. {
  465. *pbClosePipe = FALSE;
  466. return ERROR_OUTOFMEMORY;
  467. }
  468. }
  469. return ERROR_SUCCESS;
  470. }
  471. BOOL CNamedPipeClient::StartCallbackListenThread()
  472. {
  473. DWORD dwID;
  474. // Protect m_bDone and m_hthreadCallbackListen.
  475. {
  476. CInCritSec cs(&m_cs);
  477. if (m_bDone)
  478. return TRUE;
  479. m_hthreadCallbackListen =
  480. CreateThread(
  481. NULL,
  482. 0,
  483. (LPTHREAD_START_ROUTINE) CallbackListenThreadProc,
  484. this,
  485. 0,
  486. &dwID);
  487. if(m_hthreadCallbackListen == NULL)
  488. return FALSE;
  489. }
  490. // We have to make sure our callback pipe has been created before we can
  491. // continue.
  492. WaitForSingleObject(m_heventCallbackReady, INFINITE);
  493. CloseHandle(m_heventCallbackReady);
  494. m_heventCallbackReady = NULL;
  495. return TRUE;
  496. }