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.

1235 lines
31 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. fsm.cxx
  5. Abstract:
  6. Contains CFsm class implementation
  7. Contents:
  8. ContainingFsm
  9. DoFsm
  10. CFsm::CFsm
  11. CFsm::~CFsm
  12. CFsm::Push
  13. CFsm::Pop
  14. CFsm::QueueWorkItem
  15. CFsm::RunWorkItem
  16. CFsm::Run
  17. [CFsm::MapType]
  18. [CFsm::StateName]
  19. Author:
  20. Richard L Firth (rfirth) 11-Apr-1997
  21. Environment:
  22. Win32 user-mode DLL
  23. Revision History:
  24. 11-Apr-1997 rfirth
  25. Created
  26. --*/
  27. #include <wininetp.h>
  28. #include <perfdiag.hxx>
  29. #ifdef USE_DINARES_FSM_ALLOC_CACHE
  30. CRITICAL_SECTION FsmAllocCritSec;
  31. void * FsmAllocList;
  32. size_t FsmAllocSize;
  33. #endif
  34. #if INET_DEBUG
  35. struct { int size; char* name; } class_sizes[] = {
  36. sizeof(CFsm), "CFsm",
  37. sizeof(CFsm_ResolveHost), "CFsm_ResolveHost",
  38. sizeof(CFsm_FtpConnect), "CFsm_FtpConnect",
  39. sizeof(CFsm_FtpFindFirstFile), "CFsm_FtpFindFirstFile",
  40. sizeof(CFsm_FtpGetFile), "CFsm_FtpGetFile",
  41. sizeof(CFsm_FtpPutFile), "CFsm_FtpPutFile",
  42. sizeof(CFsm_FtpDeleteFile), "CFsm_FtpDeleteFile",
  43. sizeof(CFsm_FtpRenameFile), "CFsm_FtpRenameFile",
  44. sizeof(CFsm_FtpOpenFile), "CFsm_FtpOpenFile",
  45. sizeof(CFsm_FtpCreateDirectory), "CFsm_FtpCreateDirectory",
  46. sizeof(CFsm_FtpRemoveDirectory), "CFsm_FtpRemoveDirectory",
  47. sizeof(CFsm_FtpSetCurrentDirectory), "CFsm_FtpSetCurrentDirectory",
  48. sizeof(CFsm_FtpGetCurrentDirectory), "CFsm_FtpGetCurrentDirectory",
  49. sizeof(CFsm_GopherFindFirstFile), "CFsm_GopherFindFirstFile",
  50. sizeof(CFsm_GopherOpenFile), "CFsm_GopherOpenFile",
  51. sizeof(CFsm_GopherGetAttribute), "CFsm_GopherGetAttribute",
  52. sizeof(CFsm_InternetParseUrl), "CFsm_InternetParseUrl",
  53. sizeof(CFsm_InternetFindNextFile), "CFsm_InternetFindNextFile",
  54. sizeof(CFsm_InternetQueryDataAvailable), "CFsm_InternetQueryDataAvailable",
  55. sizeof(CFsm_InternetWriteFile), "CFsm_InternetWriteFile",
  56. sizeof(CFsm_InternetReadFile), "CFsm_InternetReadFile",
  57. sizeof(CFsm_SocketConnect), "CFsm_SocketConnect",
  58. sizeof(CFsm_SocketSend), "CFsm_SocketSend",
  59. sizeof(CFsm_SocketReceive), "CFsm_SocketReceive",
  60. //sizeof(CFsm_SocketDataAvailable), "CFsm_SocketDataAvailable",
  61. sizeof(CFsm_SecureConnect), "CFsm_SecureConnect",
  62. sizeof(CFsm_SecureHandshake), "CFsm_SecureHandshake",
  63. sizeof(CFsm_SecureNegotiate), "CFsm_SecureNegotiate",
  64. sizeof(CFsm_NegotiateLoop), "CFsm_NegotiateLoop",
  65. sizeof(CFsm_SecureSend), "CFsm_SecureSend",
  66. sizeof(CFsm_SecureReceive), "CFsm_SecureReceive",
  67. sizeof(CFsm_GetConnection), "CFsm_GetConnection",
  68. sizeof(CFsm_HttpSendRequest), "CFsm_HttpSendRequest",
  69. sizeof(CFsm_MakeConnection), "CFsm_MakeConnection",
  70. sizeof(CFsm_OpenConnection), "CFsm_OpenConnection",
  71. sizeof(CFsm_OpenProxyTunnel), "CFsm_OpenProxyTunnel",
  72. sizeof(CFsm_SendRequest), "CFsm_SendRequest",
  73. sizeof(CFsm_ReceiveResponse), "CFsm_ReceiveResponse",
  74. sizeof(CFsm_HttpReadData), "CFsm_HttpReadData",
  75. sizeof(CFsm_HttpWriteData), "CFsm_HttpWriteData",
  76. sizeof(CFsm_ReadData), "CFsm_ReadData",
  77. sizeof(CFsm_HttpQueryAvailable), "CFsm_HttpQueryAvailable",
  78. sizeof(CFsm_DrainResponse), "CFsm_DrainResponse",
  79. sizeof(CFsm_Redirect), "CFsm_Redirect",
  80. sizeof(CFsm_ReadLoop), "CFsm_ReadLoop",
  81. sizeof(CFsm_ParseHttpUrl), "CFsm_ParseHttpUrl",
  82. sizeof(CFsm_OpenUrl), "CFsm_OpenUrl",
  83. sizeof(CFsm_ParseUrlForHttp), "CFsm_ParseUrlForHttp",
  84. sizeof(CFsm_ReadFile), "CFsm_ReadFile",
  85. sizeof(CFsm_ReadFileEx), "CFsm_ReadFileEx",
  86. //sizeof(CFsm_WriteFile), "CFsm_WriteFile",
  87. sizeof(CFsm_BackgroundTask), "CFsm_BackgroundTask",
  88. sizeof(CFsm_QueryAvailable), "CFsm_QueryAvailable"
  89. };
  90. void dump_class_sizes() {
  91. for (int i = 0; i < ARRAY_ELEMENTS(class_sizes); ++i) {
  92. DEBUG_PRINT(ASYNC,INFO,("%s = %d\n", class_sizes[i].name, class_sizes[i].size));
  93. }
  94. }
  95. #endif
  96. //
  97. // functions
  98. //
  99. //
  100. // This is Dinarte's experiement for reducing Mem alloc on
  101. // creating FSMs.
  102. //
  103. #ifdef USE_DINARES_FSM_ALLOC_CACHE
  104. VOID
  105. FsmInitialize(
  106. VOID
  107. )
  108. /*++
  109. Routine Description:
  110. Performs initialization required by functions in this module
  111. Arguments:
  112. None.
  113. Return Value:
  114. DWORD
  115. Success - ERROR_SUCCESS
  116. Failure - return code from LocalAlloc
  117. --*/
  118. {
  119. DEBUG_ENTER((DBG_ASYNC,
  120. None,
  121. "FsmInitialize",
  122. NULL
  123. ));
  124. InitializeCriticalSection(&FsmAllocCritSec);
  125. FsmAllocSize = sizeof(CFsm);
  126. if (FsmAllocSize < sizeof(CFsm_ResolveHost))
  127. FsmAllocSize = sizeof(CFsm_ResolveHost);
  128. if (FsmAllocSize < sizeof(CFsm_SocketConnect))
  129. FsmAllocSize = sizeof(CFsm_SocketConnect);
  130. if (FsmAllocSize < sizeof(CFsm_SocketSend))
  131. FsmAllocSize = sizeof(CFsm_SocketSend);
  132. if (FsmAllocSize < sizeof(CFsm_SocketReceive))
  133. FsmAllocSize = sizeof(CFsm_SocketReceive);
  134. if (FsmAllocSize < sizeof(CFsm_SecureConnect))
  135. FsmAllocSize = sizeof(CFsm_SecureConnect);
  136. if (FsmAllocSize < sizeof(CFsm_SecureHandshake))
  137. FsmAllocSize = sizeof(CFsm_SecureHandshake);
  138. if (FsmAllocSize < sizeof(CFsm_SecureNegotiate))
  139. FsmAllocSize = sizeof(CFsm_SecureNegotiate);
  140. if (FsmAllocSize < sizeof(CFsm_NegotiateLoop))
  141. FsmAllocSize = sizeof(CFsm_NegotiateLoop);
  142. if (FsmAllocSize < sizeof(CFsm_SecureSend))
  143. FsmAllocSize = sizeof(CFsm_SecureSend);
  144. if (FsmAllocSize < sizeof(CFsm_SecureReceive))
  145. FsmAllocSize = sizeof(CFsm_SecureReceive);
  146. if (FsmAllocSize < sizeof(CFsm_GetConnection))
  147. FsmAllocSize = sizeof(CFsm_GetConnection);
  148. if (FsmAllocSize < sizeof(CFsm_HttpSendRequest))
  149. FsmAllocSize = sizeof(CFsm_HttpSendRequest);
  150. if (FsmAllocSize < sizeof(CFsm_MakeConnection))
  151. FsmAllocSize = sizeof(CFsm_MakeConnection);
  152. if (FsmAllocSize < sizeof(CFsm_OpenConnection))
  153. FsmAllocSize = sizeof(CFsm_OpenConnection);
  154. if (FsmAllocSize < sizeof(CFsm_OpenProxyTunnel))
  155. FsmAllocSize = sizeof(CFsm_OpenProxyTunnel);
  156. if (FsmAllocSize < sizeof(CFsm_SendRequest))
  157. FsmAllocSize = sizeof(CFsm_SendRequest);
  158. if (FsmAllocSize < sizeof(CFsm_ReceiveResponse))
  159. FsmAllocSize = sizeof(CFsm_ReceiveResponse);
  160. if (FsmAllocSize < sizeof(CFsm_HttpReadData))
  161. FsmAllocSize = sizeof(CFsm_HttpReadData);
  162. if (FsmAllocSize < sizeof(CFsm_HttpWriteData))
  163. FsmAllocSize = sizeof(CFsm_HttpWriteData);
  164. if (FsmAllocSize < sizeof(CFsm_ReadData))
  165. FsmAllocSize = sizeof(CFsm_ReadData);
  166. if (FsmAllocSize < sizeof(CFsm_HttpQueryAvailable))
  167. FsmAllocSize = sizeof(CFsm_HttpQueryAvailable);
  168. if (FsmAllocSize < sizeof(CFsm_DrainResponse))
  169. FsmAllocSize = sizeof(CFsm_DrainResponse);
  170. if (FsmAllocSize < sizeof(CFsm_Redirect))
  171. FsmAllocSize = sizeof(CFsm_Redirect);
  172. if (FsmAllocSize < sizeof(CFsm_ReadLoop))
  173. FsmAllocSize = sizeof(CFsm_ReadLoop);
  174. if (FsmAllocSize < sizeof(CFsm_ParseHttpUrl))
  175. FsmAllocSize = sizeof(CFsm_ParseHttpUrl);
  176. if (FsmAllocSize < sizeof(CFsm_OpenUrl))
  177. FsmAllocSize = sizeof(CFsm_OpenUrl);
  178. if (FsmAllocSize < sizeof(CFsm_ParseUrlForHttp))
  179. FsmAllocSize = sizeof(CFsm_ParseUrlForHttp);
  180. if (FsmAllocSize < sizeof(CFsm_ReadFile))
  181. FsmAllocSize = sizeof(CFsm_ReadFile);
  182. if (FsmAllocSize < sizeof(CFsm_ReadFileEx))
  183. FsmAllocSize = sizeof(CFsm_ReadFileEx);
  184. if (FsmAllocSize < sizeof(CFsm_QueryAvailable))
  185. FsmAllocSize = sizeof(CFsm_QueryAvailable);
  186. //
  187. // Pre-allocate a pool of state-machines for locality of reference
  188. //
  189. for (int cPreAlloc = 8192 / FsmAllocSize; cPreAlloc > 0; --cPreAlloc)
  190. {
  191. void * pFsm = (void *)ALLOCATE_FIXED_MEMORY(FsmAllocSize);
  192. if (pFsm == NULL)
  193. break;
  194. *(void **)pFsm = FsmAllocList;
  195. FsmAllocList = pFsm;
  196. }
  197. }
  198. VOID
  199. FsmTerminate(
  200. VOID
  201. )
  202. /*++
  203. Routine Description:
  204. Obverse of FsmInitialize - frees any system resources allocated by
  205. FsmInitialize
  206. Arguments:
  207. None.
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. DEBUG_ENTER((DBG_ASYNC,
  213. None,
  214. "FsmTerminate",
  215. NULL
  216. ));
  217. //
  218. // there shouldn't be any other threads active when this function is called
  219. // but we'll grab the critical section anyway, just to make sure
  220. //
  221. EnterCriticalSection(&FsmAllocCritSec);
  222. while (FsmAllocList)
  223. {
  224. void * pFsm = FsmAllocList;
  225. FsmAllocList = *(void **)pFsm;
  226. FREE_MEMORY((HLOCAL)pFsm);
  227. }
  228. LeaveCriticalSection(&FsmAllocCritSec);
  229. //
  230. // delete the critical section
  231. //
  232. DeleteCriticalSection(&FsmAllocCritSec);
  233. DEBUG_LEAVE(0);
  234. }
  235. #endif
  236. CFsm *
  237. ContainingFsm(
  238. IN LPVOID lpAddress
  239. )
  240. /*++
  241. Routine Description:
  242. Returns address of start of CFsm object, including vtable
  243. Arguments:
  244. lpAddress - pointer to list inside CFsm object
  245. Return Value:
  246. CFsm * - pointer to start of object
  247. --*/
  248. {
  249. return CONTAINING_RECORD(lpAddress, CFsm, m_ListEntry);
  250. }
  251. //DWORD
  252. //RunAll(
  253. // VOID
  254. // )
  255. //{
  256. // DWORD error;
  257. // LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  258. //
  259. // if (lpThreadInfo != NULL) {
  260. // while (lpThreadInfo->Fsm != NULL) {
  261. // lpThreadInfo->Fsm->Run();
  262. // }
  263. // } else {
  264. // error = ERROR_INTERNET_INTERNAL_ERROR;
  265. // }
  266. // return error;
  267. //}
  268. DWORD
  269. DoFsm(
  270. IN CFsm * pFsm
  271. )
  272. /*++
  273. Routine Description:
  274. Common FSM run processing
  275. Arguments:
  276. pFsm - FSM to run (maybe NULL if new failed)
  277. Return Value:
  278. DWORD - return code from running FSM
  279. --*/
  280. {
  281. DEBUG_ENTER((DBG_ASYNC,
  282. Dword,
  283. "DoFsm",
  284. "%#x (%s)",
  285. pFsm,
  286. pFsm->MapType()
  287. ));
  288. DWORD error;
  289. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  290. INET_ASSERT(lpThreadInfo != NULL);
  291. if (lpThreadInfo != NULL) {
  292. if (pFsm != NULL) {
  293. error = pFsm->GetError();
  294. if (error == ERROR_SUCCESS) {
  295. error = pFsm->Run(lpThreadInfo, NULL, NULL);
  296. } else {
  297. INET_ASSERT(FALSE);
  298. delete pFsm;
  299. }
  300. } else {
  301. error = ERROR_NOT_ENOUGH_MEMORY;
  302. }
  303. } else {
  304. error = ERROR_INTERNET_INTERNAL_ERROR;
  305. }
  306. DEBUG_LEAVE(error);
  307. return error;
  308. }
  309. //
  310. // methods
  311. //
  312. //
  313. // This is Dinarte's experiement for reducing Mem alloc on
  314. // creating FSMs. Not used right now.
  315. //
  316. #ifdef USE_DINARES_FSM_ALLOC_CACHE
  317. void *
  318. CFsm::operator new(
  319. IN size_t Size
  320. )
  321. /*++
  322. Routine Description:
  323. Allocates memory for the new state-machine from a special memory pool.
  324. Arguments:
  325. Size - size of the state-machine
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. VOID * pFsm;
  331. EnterCriticalSection(&FsmAllocCritSec);
  332. pFsm = FsmAllocList;
  333. if (pFsm)
  334. {
  335. FsmAllocList = *(void **)pFsm;
  336. }
  337. LeaveCriticalSection(&FsmAllocCritSec);
  338. if (pFsm == NULL)
  339. {
  340. INET_ASSERT(Size <= FsmAllocSize);
  341. pFsm = (void *)ALLOCATE_FIXED_MEMORY(FsmAllocSize);
  342. }
  343. return(pFsm);
  344. }
  345. VOID
  346. CFsm::operator delete(
  347. IN VOID * pFsm
  348. )
  349. /*++
  350. Routine Description:
  351. Deallocates memory for the state-machine by adding it to a special
  352. memory pool.
  353. Arguments:
  354. pFsm - pointer to the state-machine
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. if (pFsm)
  360. {
  361. EnterCriticalSection(&FsmAllocCritSec);
  362. *(void **)pFsm = FsmAllocList;
  363. FsmAllocList = pFsm;
  364. LeaveCriticalSection(&FsmAllocCritSec);
  365. }
  366. }
  367. #endif
  368. CFsm::CFsm(
  369. IN DWORD (* lpfnHandler)(CFsm *),
  370. IN LPVOID lpvContext
  371. ) : CPriorityListEntry(0)
  372. /*++
  373. Routine Description:
  374. CFsm constructor. This gets called many times since its the base of all the
  375. derived FSMs
  376. Arguments:
  377. lpfnHandler - state-machine handler
  378. lpvContext - callee context
  379. Return Value:
  380. None.
  381. --*/
  382. {
  383. #if INET_DEBUG
  384. static bool b = TRUE;
  385. if (b) {
  386. dump_class_sizes();
  387. b=FALSE;
  388. }
  389. #endif
  390. DEBUG_ENTER((DBG_OBJECTS,
  391. None,
  392. "CFsm::CFsm",
  393. "{%#x}",
  394. this
  395. ));
  396. INIT_FSM();
  397. m_lpThreadInfo = InternetGetThreadInfo();
  398. if (m_lpThreadInfo == NULL) {
  399. INET_ASSERT(m_lpThreadInfo != NULL);
  400. SetError(ERROR_INTERNET_INTERNAL_ERROR);
  401. DEBUG_LEAVE(0);
  402. return;
  403. }
  404. m_dwContext = m_lpThreadInfo->Context;
  405. m_hObject = m_lpThreadInfo->hObject;
  406. m_hObjectMapped = (INTERNET_HANDLE_OBJECT *)m_lpThreadInfo->hObjectMapped;
  407. m_dwMappedErrorCode = m_lpThreadInfo->dwMappedErrorCode;
  408. m_State = FSM_STATE_INIT;
  409. m_NextState = FSM_STATE_CONTINUE;
  410. m_FunctionState = FSM_STATE_BAD;
  411. m_lpfnHandler = lpfnHandler;
  412. m_lpvContext = lpvContext;
  413. SetError(ERROR_SUCCESS);
  414. Push();
  415. m_Hint = FSM_HINT_SLOW;
  416. m_Socket = INVALID_SOCKET;
  417. m_Action = FSM_ACTION_NONE;
  418. m_dwBlockId = 0;
  419. m_dwTimeout = INFINITE;
  420. m_fTimeoutWraps = FALSE;
  421. m_dwTimer = 0;
  422. m_bTimerStarted = FALSE;
  423. m_bIsBlockingFsm = FALSE;
  424. m_bIsApi = FALSE;
  425. m_ApiType = ApiType_None;
  426. m_dwApiData = 0;
  427. m_ApiResult.Handle = NULL;
  428. DEBUG_LEAVE(0);
  429. }
  430. CFsm::~CFsm()
  431. /*++
  432. Routine Description:
  433. CFsm desctructor
  434. Arguments:
  435. None.
  436. Return Value:
  437. None.
  438. --*/
  439. {
  440. DEBUG_ENTER((DBG_OBJECTS,
  441. None,
  442. "CFsm::~CFsm",
  443. "{%#x}",
  444. this
  445. ));
  446. CHECK_FSM();
  447. CHECK_OWNED();
  448. Pop();
  449. #ifdef STRESS_BUG_DEBUG
  450. m_Link = (CFsm *) (DWORD_PTR)-3;
  451. m_dwError = 0xFEFEFEFE;
  452. m_lpThreadInfo = (LPINTERNET_THREAD_INFO) (DWORD_PTR)-3;
  453. m_dwContext = 0xFEFEFEFE;
  454. m_hObject = (HINTERNET)(DWORD_PTR)-3;
  455. #endif
  456. DEBUG_LEAVE(0);
  457. }
  458. VOID
  459. CFsm::Push(
  460. VOID
  461. )
  462. /*++
  463. Routine Description:
  464. Adds this FSM to the head of the queue
  465. Arguments:
  466. None.
  467. Return Value:
  468. None.
  469. --*/
  470. {
  471. DEBUG_ENTER((DBG_ASYNC,
  472. None,
  473. "CFsm::Push",
  474. "{%#x (%s:%s)}",
  475. this,
  476. MapState(),
  477. MapFunctionState()
  478. ));
  479. CHECK_FSM();
  480. CHECK_UNOWNED();
  481. INET_ASSERT(m_lpThreadInfo != NULL);
  482. CHECK_INTERNET_THREAD_INFO(m_lpThreadInfo);
  483. m_Link = m_lpThreadInfo->Fsm;
  484. m_lpThreadInfo->Fsm = this;
  485. CHECK_FSM_OWNED(m_Link);
  486. RESET_FSM_OWNED(m_Link);
  487. DEBUG_PRINT(ASYNC,
  488. INFO,
  489. ("!!! FSM %#x unowned\n", m_Link
  490. ));
  491. SET_OWNED();
  492. DEBUG_PRINT(ASYNC,
  493. INFO,
  494. ("!!! FSM %#x owned by %#x\n",
  495. this,
  496. GetCurrentThreadId()
  497. ));
  498. DEBUG_LEAVE(0);
  499. }
  500. VOID
  501. CFsm::Pop(
  502. VOID
  503. )
  504. /*++
  505. Routine Description:
  506. Puts the next FSM (if any) at the head of the queue
  507. Arguments:
  508. None.
  509. Return Value:
  510. None.
  511. --*/
  512. {
  513. DEBUG_ENTER((DBG_ASYNC,
  514. None,
  515. "CFsm::Pop",
  516. "{%#x (%s:%s)}",
  517. this,
  518. MapState(),
  519. MapFunctionState()
  520. ));
  521. INET_ASSERT(m_lpThreadInfo != NULL);
  522. CHECK_INTERNET_THREAD_INFO(m_lpThreadInfo);
  523. CHECK_FSM();
  524. CHECK_OWNED();
  525. CHECK_FSM_UNOWNED(m_Link);
  526. CFsm * pNextFsm = m_Link;
  527. m_lpThreadInfo->Fsm = pNextFsm;
  528. SET_FSM_OWNED(pNextFsm);
  529. DEBUG_PRINT(ASYNC,
  530. INFO,
  531. ("!!! FSM %#x owned by %#x\n",
  532. pNextFsm,
  533. GetCurrentThreadId()
  534. ));
  535. if (pNextFsm != NULL) {
  536. pNextFsm->SetState(pNextFsm->GetNextState());
  537. pNextFsm->SetError(GetError());
  538. DEBUG_PRINT(ASYNC,
  539. INFO,
  540. ("next FSM %#x (%s), state %s, function-state %s\n",
  541. pNextFsm,
  542. pNextFsm->MapType(),
  543. pNextFsm->MapState(),
  544. pNextFsm->MapFunctionState()
  545. ));
  546. } else {
  547. DEBUG_PRINT(ASYNC,
  548. INFO,
  549. ("last FSM\n"
  550. ));
  551. }
  552. DEBUG_LEAVE(0);
  553. }
  554. DWORD
  555. CFsm::QueueWorkItem(
  556. VOID
  557. )
  558. /*++
  559. Routine Description:
  560. Queues this FSM to worker thread for processing. Worker thread callback is
  561. CFsm::RunWorkItem
  562. Arguments:
  563. None.
  564. Return Value:
  565. DWORD
  566. Success - ERROR_SUCCESS
  567. Failure - return code from SHQueueUserWorkItem
  568. --*/
  569. {
  570. DEBUG_ENTER((DBG_ASYNC,
  571. Dword,
  572. "CFsm::QueueWorkItem",
  573. "{%#x [%s, socket %#x, block id %#x, timeout %#x, error %d, state %s:%s]}",
  574. this,
  575. MapType(),
  576. GetSocket(),
  577. GetBlockId(),
  578. GetTimeout(),
  579. GetError(),
  580. MapState(),
  581. MapFunctionState()
  582. ));
  583. DWORD error = ERROR_IO_PENDING;
  584. RESET_OWNED();
  585. if (SHQueueUserWorkItem((LPTHREAD_START_ROUTINE)RunWorkItem,
  586. this,
  587. 0,
  588. (DWORD_PTR)0,
  589. (DWORD_PTR *)NULL,
  590. NULL,
  591. 0)) {
  592. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  593. INET_ASSERT(lpThreadInfo != NULL);
  594. if (lpThreadInfo != NULL) {
  595. lpThreadInfo->Fsm = NULL;
  596. }
  597. } else {
  598. error = GetLastError();
  599. }
  600. INET_ASSERT(error == ERROR_IO_PENDING);
  601. DEBUG_LEAVE(error);
  602. return error;
  603. }
  604. DWORD
  605. CFsm::RunWorkItem(
  606. IN CFsm * pFsm
  607. )
  608. /*++
  609. Routine Description:
  610. Run the current work item to the next block state or completion. This
  611. (class static) function is called in the context of a system thread pool
  612. callback function
  613. Arguments:
  614. pFsm - pointer to FSM to run
  615. Return Value:
  616. DWORD
  617. Success - ERROR_SUCCESS
  618. Failure - ERROR_INTERNET_INTERNAL_ERROR
  619. --*/
  620. {
  621. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  622. INET_ASSERT(lpThreadInfo != NULL);
  623. if (lpThreadInfo == NULL) {
  624. INET_ASSERT(FALSE);
  625. return ERROR_INTERNET_INTERNAL_ERROR;
  626. }
  627. lpThreadInfo->IsAsyncWorkerThread = TRUE;
  628. DEBUG_ENTER((DBG_ASYNC,
  629. Dword,
  630. "RunWorkItem",
  631. "%#x",
  632. pFsm
  633. ));
  634. PERF_ENTER(Worker);
  635. DWORD error;
  636. DEBUG_PRINT(ASYNC,
  637. INFO,
  638. ("%s Fsm %#x: socket %#x, block id %#x, timeout %#x, error %d\n",
  639. pFsm->MapType(),
  640. pFsm,
  641. pFsm->GetSocket(),
  642. pFsm->GetBlockId(),
  643. pFsm->GetTimeout(),
  644. pFsm->GetError()
  645. ));
  646. while (TRUE) {
  647. INET_ASSERT(pFsm != NULL);
  648. BOOL bIsApi = pFsm->IsApi();
  649. API_TYPE apiType = pFsm->GetApiType();
  650. lpThreadInfo->Fsm = pFsm;
  651. SET_FSM_OWNED(pFsm);
  652. DWORD dwResult=0;
  653. DWORD dwApiData=0;
  654. if (pFsm->IsInvalid())
  655. {
  656. pFsm->SetErrorState(ERROR_INTERNET_OPERATION_CANCELLED);
  657. pFsm->Run(lpThreadInfo, &dwResult, &dwApiData);
  658. error = ERROR_INTERNET_OPERATION_CANCELLED;
  659. }
  660. else
  661. {
  662. error = pFsm->Run(lpThreadInfo, &dwResult, &dwApiData);
  663. }
  664. //
  665. // We should follow the following rules for this.
  666. //
  667. // 1) If Operation Failed
  668. //
  669. // error != ERROR_SUCCESS && dwResult == 0
  670. //
  671. // To assign fields of INTERNET_ASYNC_RESULT, do:
  672. //
  673. // INTERNET_ASYNC_RESULT.dwResult = 0
  674. // INTERNET_ASYNC_RESULT.dwError = error
  675. // 2) If operation Succeeded
  676. //
  677. // error == ERROR_SUCCESS && dwResult != 0
  678. //
  679. // To assign fields of INTERNET_ASYNC_RESULT, do:
  680. //
  681. // if( ApiReturnType == HINTERNET )
  682. // INTERNET_ASYNC_RESULT.dwResult = (HINTERNET)dwApiResult
  683. // else
  684. // if( ApiReturnType == BOOL )
  685. // INTERNET_ASYNC_RESULT.dwResult = TRUE
  686. // endif
  687. // endif
  688. //
  689. // INTERNET_ASYNC_RESULT.dwError = dwApiData
  690. DEBUG_PRINT(ASYNC,
  691. INFO,
  692. ("dwResult = %d [%#x], dwApiData=%d [%#x], apiType = %s, error = %d\n",
  693. dwResult, dwResult,
  694. dwApiData, dwApiData,
  695. (apiType==ApiType_Handle)?"HANDLE":"BOOL",
  696. error));
  697. if (error == ERROR_IO_PENDING) {
  698. break;
  699. }
  700. pFsm = lpThreadInfo->Fsm;
  701. if (pFsm == NULL) {
  702. if (bIsApi
  703. && ((INTERNET_HANDLE_OBJECT *)lpThreadInfo->hObjectMapped)
  704. ->IsAsyncHandle()) {
  705. INET_ASSERT((apiType == ApiType_Handle)
  706. || (apiType == ApiType_Bool));
  707. INTERNET_ASYNC_RESULT asyncResult;
  708. /*
  709. asyncResult.dwResult = (apiType == ApiType_Handle)
  710. ? dwResult
  711. : (BOOL)(error == ERROR_SUCCESS);
  712. */
  713. asyncResult.dwResult = (error == ERROR_SUCCESS
  714. ?((apiType == ApiType_Handle)
  715. ? dwResult
  716. : TRUE)
  717. :0);
  718. //
  719. // InternetQueryDataAvailable uses dwApiData to return the
  720. // number of bytes available, in addition to returning the
  721. // the value through the lpdwNumberOfBytesAvailable parameter
  722. //
  723. asyncResult.dwError = (error == ERROR_SUCCESS)
  724. ? dwApiData
  725. : error;
  726. SetLastError(error);
  727. //INET_ASSERT(((INTERNET_HANDLE_OBJECT *)lpThreadInfo->hObjectMapped)
  728. // ->GetObjectType() == TypeHttpRequestHandle);
  729. InternetIndicateStatus(INTERNET_STATUS_REQUEST_COMPLETE,
  730. (LPVOID)&asyncResult,
  731. sizeof(asyncResult)
  732. );
  733. //INET_ASSERT(((INTERNET_HANDLE_OBJECT *)lpThreadInfo->hObjectMapped)
  734. // ->GetObjectType() == TypeHttpRequestHandle);
  735. DereferenceObject((LPVOID)lpThreadInfo->hObjectMapped);
  736. }
  737. break;
  738. } else if (bIsApi) {
  739. //
  740. // completing an async API that is not the last in the chain.
  741. // Typically, HttpSendRequest() within InternetOpenUrl()
  742. //
  743. DereferenceObject((LPVOID)lpThreadInfo->hObjectMapped);
  744. }
  745. }
  746. lpThreadInfo->IsAsyncWorkerThread = FALSE;
  747. PERF_LEAVE(Worker);
  748. DEBUG_LEAVE(error);
  749. return error;
  750. }
  751. DWORD
  752. CFsm::Run(
  753. IN LPINTERNET_THREAD_INFO lpThreadInfo,
  754. OUT DWORD *lpdwApiResult OPTIONAL,
  755. OUT DWORD *lpdwApiData OPTIONAL
  756. )
  757. /*++
  758. Routine Description:
  759. Runs the state handler for this FSM
  760. Arguments:
  761. lpThreadInfo - INTERNET_THREAD_INFO for this thread
  762. lpdwApiResult - where optional API result is written
  763. lpdwApiData - where optional API data iswritten
  764. Return Value:
  765. DWORD - return code from state handler
  766. --*/
  767. {
  768. DEBUG_ENTER((DBG_ASYNC,
  769. Dword,
  770. "CFsm::Run",
  771. "%#x, %#x [%#x], %#x [%#x]",
  772. lpThreadInfo,
  773. lpdwApiResult,
  774. (lpdwApiResult?*lpdwApiResult:NULL),
  775. lpdwApiData,
  776. (lpdwApiData?*lpdwApiData:NULL)
  777. ));
  778. CHECK_FSM();
  779. CHECK_OWNED();
  780. INET_ASSERT(lpThreadInfo != NULL);
  781. INET_ASSERT(lpThreadInfo->Fsm != NULL);
  782. DWORD error = ERROR_SUCCESS;
  783. lpThreadInfo->Context = m_dwContext;
  784. _InternetSetObjectHandle(lpThreadInfo, m_hObject, m_hObjectMapped);
  785. m_lpThreadInfo = lpThreadInfo;
  786. while (TRUE) {
  787. DEBUG_PRINT(ASYNC,
  788. INFO,
  789. ("%s Fsm %#x state %s (%d) function-state %s (%d) error %s (%d)\n",
  790. MapType(),
  791. this,
  792. MapState(),
  793. GetState(),
  794. MapFunctionState(),
  795. GetFunctionState(),
  796. InternetMapError(GetError()),
  797. GetError()
  798. ));
  799. error = (*m_lpfnHandler)(this);
  800. if (error == ERROR_IO_PENDING) {
  801. break;
  802. }
  803. SetError(error);
  804. SetMappedError(lpThreadInfo->dwMappedErrorCode);
  805. if (IsDone()) {
  806. DEBUG_PRINT(ASYNC,
  807. INFO,
  808. ("%s Fsm %#x done, next is %s %#x\n",
  809. MapType(),
  810. this,
  811. m_Link ? m_Link->MapType() : "",
  812. m_Link
  813. ));
  814. if (lpdwApiResult != NULL) {
  815. *lpdwApiResult = GetApiResult();
  816. }
  817. if (lpdwApiData != NULL) {
  818. *lpdwApiData = GetApiData();
  819. }
  820. DEBUG_PRINT(ASYNC,
  821. INFO,
  822. ("Fsm %#x finished with lpdwApiResult = %#x[%#x], lpdwApiData = %#x[%#x]\n",
  823. this,
  824. lpdwApiResult,
  825. (lpdwApiResult == NULL)?NULL:*lpdwApiResult,
  826. lpdwApiData,
  827. (lpdwApiData == NULL)?NULL:*lpdwApiData
  828. ));
  829. delete this;
  830. break;
  831. }
  832. SetState(GetNextState());
  833. }
  834. DEBUG_LEAVE(error);
  835. return error;
  836. }
  837. #if INET_DEBUG
  838. #if !defined(CASE_OF)
  839. #define CASE_OF(x) case x: return #x
  840. #endif
  841. DEBUG_FUNCTION
  842. LPSTR
  843. CFsm::MapType(
  844. VOID
  845. ) {
  846. switch (m_Type) {
  847. case FSM_TYPE_NONE: return "NONE";
  848. case FSM_TYPE_WAIT_FOR_COMPLETION: return "WAIT_FOR_COMPLETION";
  849. case FSM_TYPE_RESOLVE_HOST: return "RESOLVE_HOST";
  850. case FSM_TYPE_SOCKET_CONNECT: return "SOCKET_CONNECT";
  851. case FSM_TYPE_SOCKET_SEND: return "SOCKET_SEND";
  852. case FSM_TYPE_SOCKET_RECEIVE: return "SOCKET_RECEIVE";
  853. case FSM_TYPE_SOCKET_QUERY_AVAILABLE: return "SOCKET_QUERY_AVAILABLE";
  854. case FSM_TYPE_SECURE_CONNECT: return "SECURE_CONNECT";
  855. case FSM_TYPE_SECURE_HANDSHAKE: return "SECURE_HANDSHAKE";
  856. case FSM_TYPE_SECURE_NEGOTIATE: return "SECURE_NEGOTIATE";
  857. case FSM_TYPE_NEGOTIATE_LOOP: return "NEGOTIATE_LOOP";
  858. case FSM_TYPE_SECURE_SEND: return "SECURE_SEND";
  859. case FSM_TYPE_SECURE_RECEIVE: return "SECURE_RECEIVE";
  860. case FSM_TYPE_GET_CONNECTION: return "GET_CONNECTION";
  861. case FSM_TYPE_HTTP_SEND_REQUEST: return "HTTP_SEND_REQUEST";
  862. case FSM_TYPE_MAKE_CONNECTION: return "MAKE_CONNECTION";
  863. case FSM_TYPE_OPEN_CONNECTION: return "OPEN_CONNECTION";
  864. case FSM_TYPE_OPEN_PROXY_TUNNEL: return "OPEN_PROXY_TUNNEL";
  865. case FSM_TYPE_SEND_REQUEST: return "SEND_REQUEST";
  866. case FSM_TYPE_RECEIVE_RESPONSE: return "RECEIVE_RESPONSE";
  867. case FSM_TYPE_HTTP_READ: return "HTTP_READ";
  868. case FSM_TYPE_HTTP_WRITE: return "HTTP_WRITE";
  869. case FSM_TYPE_READ_DATA: return "READ_DATA";
  870. case FSM_TYPE_HTTP_QUERY_AVAILABLE: return "HTTP_QUERY_AVAILABLE";
  871. case FSM_TYPE_DRAIN_RESPONSE: return "DRAIN_RESPONSE";
  872. case FSM_TYPE_REDIRECT: return "REDIRECT";
  873. case FSM_TYPE_READ_LOOP: return "READ_LOOP";
  874. case FSM_TYPE_PARSE_HTTP_URL: return "PARSE_HTTP_URL";
  875. case FSM_TYPE_PARSE_URL_FOR_HTTP: return "PARSE_URL_FOR_HTTP";
  876. case FSM_TYPE_READ_FILE: return "READ_FILE";
  877. case FSM_TYPE_READ_FILE_EX: return "READ_FILE_EX";
  878. case FSM_TYPE_WRITE_FILE: return "WRITE_FILE";
  879. case FSM_TYPE_QUERY_DATA_AVAILABLE: return "QUERY_DATA_AVAILABLE";
  880. case FSM_TYPE_FTP_CONNECT: return "FTP_CONNECT";
  881. case FSM_TYPE_FTP_FIND_FIRST_FILE: return "FTP_FIND_FIRST_FILE";
  882. case FSM_TYPE_FTP_GET_FILE: return "FTP_GET_FILE";
  883. case FSM_TYPE_FTP_PUT_FILE: return "FTP_PUT_FILE";
  884. case FSM_TYPE_FTP_DELETE_FILE: return "FTP_DELETE_FILE";
  885. case FSM_TYPE_FTP_RENAME_FILE: return "FTP_RENAME_FILE";
  886. case FSM_TYPE_FTP_OPEN_FILE: return "FTP_OPEN_FILE";
  887. case FSM_TYPE_FTP_CREATE_DIRECTORY: return "FTP_CREATE_DIRECTORY";
  888. case FSM_TYPE_FTP_REMOVE_DIRECTORY: return "FTP_REMOVE_DIRECTORY";
  889. case FSM_TYPE_FTP_SET_CURRENT_DIRECTORY: return "FTP_SET_CURRENT_DIRECTORY";
  890. case FSM_TYPE_FTP_GET_CURRENT_DIRECTORY: return "FTP_GET_CURRENT_DIRECTORY";
  891. case FSM_TYPE_GOPHER_FIND_FIRST_FILE: return "GOPHER_FIND_FIRST_FILE";
  892. case FSM_TYPE_GOPHER_OPEN_FILE: return "GOPHER_OPEN_FILE";
  893. case FSM_TYPE_GOPHER_GET_ATTRIBUTE: return "GOPHER_GET_ATTRIBUTE";
  894. case FSM_TYPE_INTERNET_PARSE_URL: return "INTERNET_PARSE_URL";
  895. case FSM_TYPE_INTERNET_FIND_NEXT_FILE: return "INTERNET_FIND_NEXT_FILE";
  896. case FSM_TYPE_INTERNET_QUERY_DATA_AVAILABLE: return "INTERNET_QUERY_DATA_AVAILABLE";
  897. case FSM_TYPE_INTERNET_WRITE_FILE: return "INTERNET_WRITE_FILE";
  898. case FSM_TYPE_INTERNET_READ_FILE: return "INTERNET_READ_FILE";
  899. }
  900. return "?";
  901. }
  902. DEBUG_FUNCTION
  903. LPSTR
  904. CFsm::StateName(
  905. IN DWORD State
  906. ) {
  907. switch (State) {
  908. CASE_OF(FSM_STATE_BAD);
  909. CASE_OF(FSM_STATE_INIT);
  910. CASE_OF(FSM_STATE_WAIT);
  911. CASE_OF(FSM_STATE_DONE);
  912. CASE_OF(FSM_STATE_ERROR);
  913. CASE_OF(FSM_STATE_CONTINUE);
  914. CASE_OF(FSM_STATE_FINISH);
  915. CASE_OF(FSM_STATE_1);
  916. CASE_OF(FSM_STATE_2);
  917. CASE_OF(FSM_STATE_3);
  918. CASE_OF(FSM_STATE_4);
  919. CASE_OF(FSM_STATE_5);
  920. CASE_OF(FSM_STATE_6);
  921. CASE_OF(FSM_STATE_7);
  922. CASE_OF(FSM_STATE_8);
  923. CASE_OF(FSM_STATE_9);
  924. CASE_OF(FSM_STATE_10);
  925. }
  926. return "?";
  927. }
  928. #endif // INET_DEBUG