Source code of Windows XP (NT5)
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.

25596 lines
732 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2001
  3. Module Name:
  4. HTTP2.cxx
  5. Abstract:
  6. HTTP2 transport-specific functions.
  7. Author:
  8. KamenM 08-30-01 Created
  9. Revision History:
  10. --*/
  11. #include <precomp.hxx>
  12. #include <rpcssl.h>
  13. #include <CharConv.hxx>
  14. #include <HttpRTS.hxx>
  15. #include <sdict.hxx>
  16. #include <binding.hxx>
  17. #include <Cookie.hxx>
  18. #include <Http2Log.hxx>
  19. #include <WHttpImp.hxx>
  20. // external definition
  21. TRANS_INFO *
  22. GetLoadedClientTransportInfoFromId (
  23. IN unsigned short TransportId
  24. );
  25. BOOL DefaultChannelLifetimeStringRead = FALSE;
  26. #if DBG
  27. ULONG DefaultChannelLifetime = 128 * 1024; // 128K for now
  28. char *DefaultChannelLifetimeString = "131072";
  29. ULONG DefaultChannelLifetimeStringLength = 6; // does not include null terminator
  30. #else
  31. ULONG DefaultChannelLifetime = 1024 * 1024 * 1024; // 1GB for now
  32. char *DefaultChannelLifetimeString = "1073741824";
  33. ULONG DefaultChannelLifetimeStringLength = 11; // does not include null terminator
  34. #endif
  35. ULONG DefaultReceiveWindowSize = 64 * 1024; // 64K
  36. const ULONG ClientReservedChannelLifetime = 4 * 1024; // 4K
  37. const ULONG ServerReservedChannelLifetime = 8 * 1024; // 8K
  38. const ULONG DefaultReplacementChannelCallTimeout = 3 * 60 * 1000; // 3 minutes in milliseconds
  39. const ULONG MinimumConnectionTimeout = 30 * 1000; // 30 seconds in milliseconds
  40. BOOL ActAsSeparateMachinesOnWebFarm = FALSE;
  41. BOOL AlwaysUseWinHttp = FALSE;
  42. long ChannelIdCounter = 0;
  43. ULONG HTTP2ClientReceiveWindow = HTTP2DefaultClientReceiveWindow;
  44. ULONG HTTP2InProxyReceiveWindow = HTTP2DefaultInProxyReceiveWindow;
  45. ULONG HTTP2OutProxyReceiveWindow = HTTP2DefaultOutProxyReceiveWindow;
  46. ULONG HTTP2ServerReceiveWindow = HTTP2DefaultServerReceiveWindow;
  47. ULONG OverrideMinimumConnectionTimeout = 0;
  48. RPC_CHAR *InChannelTargetTestOverride = NULL;
  49. RPC_CHAR *OutChannelTargetTestOverride = NULL;
  50. /*********************************************************************
  51. Global Functions and utility classes
  52. *********************************************************************/
  53. static const RPC_CHAR *HTTP_DEF_CHANNEL_LIFE_KEY = RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  54. RPC_STATUS InitializeDefaultChannelLifetime (
  55. void
  56. )
  57. /*++
  58. Routine Description:
  59. Read the default channel lifetime from the registry and
  60. initialize the default global variable
  61. Arguments:
  62. Return Value:
  63. RPC_S_OK or RPC_S_* error
  64. --*/
  65. {
  66. HKEY h = 0;
  67. DWORD DwordSize;
  68. DWORD Type;
  69. DWORD Result;
  70. char Buffer[20];
  71. if (DefaultChannelLifetimeStringRead)
  72. return RPC_S_OK;
  73. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  74. (PWSTR)HTTP_DEF_CHANNEL_LIFE_KEY,
  75. 0,
  76. KEY_READ,
  77. &h);
  78. if (Status == ERROR_FILE_NOT_FOUND)
  79. {
  80. // no key, proceed with static defaults
  81. return RPC_S_OK;
  82. }
  83. else if (Status != ERROR_SUCCESS)
  84. {
  85. return RPC_S_OUT_OF_MEMORY;
  86. }
  87. DwordSize = sizeof(DWORD);
  88. Status = RegQueryValueExW(
  89. h,
  90. L"DefaultChannelLifetime",
  91. 0,
  92. &Type,
  93. (LPBYTE) &Result,
  94. &DwordSize
  95. );
  96. if (Status == ERROR_FILE_NOT_FOUND)
  97. {
  98. if (h)
  99. {
  100. RegCloseKey(h);
  101. }
  102. // no key, proceed with static defaults
  103. return RPC_S_OK;
  104. }
  105. if (Status == ERROR_SUCCESS
  106. && Type == REG_DWORD)
  107. {
  108. DefaultChannelLifetime = Result;
  109. RpcpItoa(Result, Buffer, 10);
  110. DefaultChannelLifetimeStringLength = RpcpStringLengthA(Buffer);
  111. DefaultChannelLifetimeString = new char [DefaultChannelLifetimeStringLength + 1];
  112. if (DefaultChannelLifetimeString == NULL)
  113. Status = RPC_S_OUT_OF_MEMORY;
  114. else
  115. {
  116. RpcpMemoryCopy(DefaultChannelLifetimeString, Buffer, DefaultChannelLifetimeStringLength + 1);
  117. DefaultChannelLifetimeStringRead = TRUE;
  118. }
  119. }
  120. // if the type was not REG_DWORD, probably registry is corrupted
  121. // in this case, simply return success, since we don't want a corrupted
  122. // registry to hose the whole machine
  123. if (h)
  124. {
  125. RegCloseKey(h);
  126. }
  127. return Status;
  128. }
  129. static const RPC_CHAR *HTTP_ACT_AS_WEB_FARM_KEY = RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  130. RPC_STATUS InitializeActAsWebFarm (
  131. void
  132. )
  133. /*++
  134. Routine Description:
  135. Read the act as web farm variable. Used as a test hook to emulate
  136. web farm on single machine
  137. Arguments:
  138. Return Value:
  139. RPC_S_OK or RPC_S_* error
  140. --*/
  141. {
  142. HKEY h = 0;
  143. DWORD DwordSize;
  144. DWORD Type;
  145. DWORD Result;
  146. char Buffer[20];
  147. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  148. (PWSTR)HTTP_ACT_AS_WEB_FARM_KEY,
  149. 0,
  150. KEY_READ,
  151. &h);
  152. if (Status == ERROR_FILE_NOT_FOUND)
  153. {
  154. // no key, proceed with static defaults
  155. return RPC_S_OK;
  156. }
  157. else if (Status != ERROR_SUCCESS)
  158. {
  159. return RPC_S_OUT_OF_MEMORY;
  160. }
  161. DwordSize = sizeof(DWORD);
  162. Status = RegQueryValueExW(
  163. h,
  164. L"ActAsWebFarm",
  165. 0,
  166. &Type,
  167. (LPBYTE) &Result,
  168. &DwordSize
  169. );
  170. if (Status == ERROR_FILE_NOT_FOUND)
  171. {
  172. if (h)
  173. {
  174. RegCloseKey(h);
  175. }
  176. // no key, proceed with static defaults
  177. return RPC_S_OK;
  178. }
  179. if (Status == ERROR_SUCCESS
  180. && Type == REG_DWORD)
  181. {
  182. ActAsSeparateMachinesOnWebFarm = Result;
  183. }
  184. // if the type was not REG_DWORD, probably registry is corrupted
  185. // in this case, simply return success, since we don't want a corrupted
  186. // registry to hose the whole machine
  187. if (h)
  188. {
  189. RegCloseKey(h);
  190. }
  191. return Status;
  192. }
  193. static const RPC_CHAR *HTTP_USE_HTTP_KEY = RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  194. RPC_STATUS InitializeUseWinHttp (
  195. void
  196. )
  197. /*++
  198. Routine Description:
  199. Read the use WinHttp variable. Used as a test hook to force
  200. WinHttp usage regardless of security
  201. Arguments:
  202. Return Value:
  203. RPC_S_OK or RPC_S_* error
  204. --*/
  205. {
  206. #if 1
  207. // always use WinHttp for now
  208. return RPC_S_OK;
  209. #else
  210. HKEY h = 0;
  211. DWORD DwordSize;
  212. DWORD Type;
  213. DWORD Result;
  214. char Buffer[20];
  215. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  216. (PWSTR)HTTP_ACT_AS_WEB_FARM_KEY,
  217. 0,
  218. KEY_READ,
  219. &h);
  220. if (Status == ERROR_FILE_NOT_FOUND)
  221. {
  222. // no key, proceed with static defaults
  223. return RPC_S_OK;
  224. }
  225. else if (Status != ERROR_SUCCESS)
  226. {
  227. return RPC_S_OUT_OF_MEMORY;
  228. }
  229. DwordSize = sizeof(DWORD);
  230. Status = RegQueryValueExW(
  231. h,
  232. L"UseWinHttp",
  233. 0,
  234. &Type,
  235. (LPBYTE) &Result,
  236. &DwordSize
  237. );
  238. if (Status == ERROR_FILE_NOT_FOUND)
  239. {
  240. if (h)
  241. {
  242. RegCloseKey(h);
  243. }
  244. // no key, proceed with static defaults
  245. return RPC_S_OK;
  246. }
  247. if (Status == ERROR_SUCCESS
  248. && Type == REG_DWORD)
  249. {
  250. AlwaysUseWinHttp = Result;
  251. }
  252. // if the type was not REG_DWORD, probably registry is corrupted
  253. // in this case, simply return success, since we don't want a corrupted
  254. // registry to hose the whole machine
  255. if (h)
  256. {
  257. RegCloseKey(h);
  258. }
  259. return Status;
  260. #endif
  261. }
  262. static const RPC_CHAR *HTTP_RECEIVE_WINDOWS_KEY = RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  263. RPC_STATUS InitializeReceiveWindows (
  264. void
  265. )
  266. /*++
  267. Routine Description:
  268. Read the receive windows.
  269. Arguments:
  270. Return Value:
  271. RPC_S_OK or RPC_S_* error
  272. --*/
  273. {
  274. HKEY h = 0;
  275. DWORD DwordSize;
  276. DWORD Type;
  277. DWORD Result;
  278. char Buffer[20];
  279. RPC_CHAR *Keys[4];
  280. ULONG *Values[4];
  281. int i;
  282. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  283. (PWSTR)HTTP_RECEIVE_WINDOWS_KEY,
  284. 0,
  285. KEY_READ,
  286. &h);
  287. if (Status == ERROR_FILE_NOT_FOUND)
  288. {
  289. // no key, proceed with static defaults
  290. return RPC_S_OK;
  291. }
  292. else if (Status != ERROR_SUCCESS)
  293. {
  294. return RPC_S_OUT_OF_MEMORY;
  295. }
  296. Keys[0] = L"ClientReceiveWindow";
  297. Keys[1] = L"InProxyReceiveWindow";
  298. Keys[2] = L"OutProxyReceiveWindow";
  299. Keys[3] = L"ServerReceiveWindow";
  300. Values[0] = &HTTP2ClientReceiveWindow;
  301. Values[1] = &HTTP2InProxyReceiveWindow;
  302. Values[2] = &HTTP2OutProxyReceiveWindow;
  303. Values[3] = &HTTP2ServerReceiveWindow;
  304. for (i = 0; i < 4; i ++)
  305. {
  306. DwordSize = sizeof(DWORD);
  307. Status = RegQueryValueExW(
  308. h,
  309. Keys[i],
  310. 0,
  311. &Type,
  312. (LPBYTE) &Result,
  313. &DwordSize
  314. );
  315. if (Status == ERROR_SUCCESS
  316. && Type == REG_DWORD)
  317. {
  318. *(Values[i]) = Result;
  319. }
  320. }
  321. // if the type was not REG_DWORD, probably registry is corrupted
  322. // in this case, simply return success, since we don't want a corrupted
  323. // registry to hose the whole machine
  324. if (h)
  325. {
  326. RegCloseKey(h);
  327. }
  328. return RPC_S_OK;
  329. }
  330. // N.B. This value must agree with the key specified in the system.adm file
  331. static const RPC_CHAR *HTTP_MIN_CONN_TIMEOUT_KEY =
  332. L"Software\\Policies\\Microsoft\\Windows NT\\Rpc\\MinimumConnectionTimeout";
  333. RPC_STATUS InitializeMinConnectionTimeout (
  334. void
  335. )
  336. /*++
  337. Routine Description:
  338. Read the minimum connection timeout from the registry/policy.
  339. An admin may set a lower timeout than the IIS timeout.
  340. Arguments:
  341. Return Value:
  342. RPC_S_OK or RPC_S_* error
  343. --*/
  344. {
  345. HKEY h = 0;
  346. DWORD DwordSize;
  347. DWORD Type;
  348. DWORD Result;
  349. char Buffer[20];
  350. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  351. HTTP_MIN_CONN_TIMEOUT_KEY,
  352. 0,
  353. KEY_READ,
  354. &h);
  355. if (Status == ERROR_FILE_NOT_FOUND)
  356. {
  357. // no key, proceed with static defaults
  358. return RPC_S_OK;
  359. }
  360. else if (Status != ERROR_SUCCESS)
  361. {
  362. return RPC_S_OUT_OF_MEMORY;
  363. }
  364. DwordSize = sizeof(DWORD);
  365. Status = RegQueryValueExW(
  366. h,
  367. L"MinimumConnectionTimeout",
  368. 0,
  369. &Type,
  370. (LPBYTE) &Result,
  371. &DwordSize
  372. );
  373. if (Status == ERROR_FILE_NOT_FOUND)
  374. {
  375. if (h)
  376. {
  377. RegCloseKey(h);
  378. }
  379. // no key, proceed with static defaults
  380. return RPC_S_OK;
  381. }
  382. if (Status == ERROR_SUCCESS
  383. && Type == REG_DWORD
  384. && Result >= 90
  385. && Result <= 14400)
  386. {
  387. OverrideMinimumConnectionTimeout = Result * 1000;
  388. }
  389. // if the type was not REG_DWORD or out of range, probably registry is corrupted
  390. // in this case, simply return success, since we don't want a corrupted
  391. // registry to hose the whole machine
  392. if (h)
  393. {
  394. RegCloseKey(h);
  395. }
  396. return Status;
  397. }
  398. // N.B. This value must agree with the key specified in the system.adm file
  399. static const RPC_CHAR *LM_COMPATIBILITY_LEVEL_KEY =
  400. L"System\\Currentcontrolset\\Control\\Lsa";
  401. RPC_STATUS IsLanManHashDisabled (
  402. OUT BOOL *Disabled
  403. )
  404. /*++
  405. Routine Description:
  406. Check in the registry whether the lan man hash was disabled.
  407. Arguments:
  408. Disabled - on successful output, if true, the lan man hash was disabled.
  409. Undefined on failure.
  410. Return Value:
  411. RPC_S_OK or RPC_S_* error
  412. --*/
  413. {
  414. HKEY h = 0;
  415. DWORD DwordSize;
  416. DWORD Type;
  417. DWORD Result;
  418. char Buffer[20];
  419. *Disabled = FALSE;
  420. DWORD Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  421. LM_COMPATIBILITY_LEVEL_KEY,
  422. 0,
  423. KEY_READ,
  424. &h);
  425. if (Status == ERROR_FILE_NOT_FOUND)
  426. {
  427. // no key, proceed as if the hash is enabled
  428. return RPC_S_OK;
  429. }
  430. else if (Status != ERROR_SUCCESS)
  431. {
  432. return RPC_S_OUT_OF_MEMORY;
  433. }
  434. DwordSize = sizeof(DWORD);
  435. Status = RegQueryValueExW(
  436. h,
  437. L"lmcompatibilitylevel",
  438. 0,
  439. &Type,
  440. (LPBYTE) &Result,
  441. &DwordSize
  442. );
  443. if (Status == ERROR_FILE_NOT_FOUND)
  444. {
  445. if (h)
  446. {
  447. RegCloseKey(h);
  448. }
  449. // no key, proceed as if hash is enabled
  450. return RPC_S_OK;
  451. }
  452. if (Status == ERROR_SUCCESS
  453. && Type == REG_DWORD
  454. && Result >= 2)
  455. {
  456. *Disabled = TRUE;
  457. }
  458. // if the type was not REG_DWORD or out of range, probably registry is corrupted
  459. // in this case, assume hash is enabled
  460. if (h)
  461. {
  462. RegCloseKey(h);
  463. }
  464. return Status;
  465. }
  466. BOOL g_fHttpClientInitialized = FALSE;
  467. BOOL g_fHttpServerInitialized = FALSE;
  468. TRANS_INFO *HTTPTransInfo = NULL;
  469. RPC_STATUS InitializeHttpCommon (
  470. void
  471. )
  472. /*++
  473. Routine Description:
  474. Initialize the common (b/n client & server) Http transport
  475. if not done already
  476. Arguments:
  477. Return Value:
  478. RPC_S_OK or RPC_S_* error
  479. --*/
  480. {
  481. RPC_STATUS RpcStatus;
  482. GlobalMutexVerifyOwned();
  483. if (HTTPTransInfo == NULL)
  484. {
  485. HTTPTransInfo = GetLoadedClientTransportInfoFromId(HTTP_TOWER_ID);
  486. // the TCP transport should have been initialized by now
  487. ASSERT(HTTPTransInfo);
  488. }
  489. return InitializeReceiveWindows();
  490. }
  491. RPC_STATUS InitializeHttpClient (
  492. void
  493. )
  494. /*++
  495. Routine Description:
  496. Initialize the Http client if not done already
  497. Arguments:
  498. Return Value:
  499. RPC_S_OK or RPC_S_* error
  500. --*/
  501. {
  502. RPC_STATUS RpcStatus;
  503. GlobalMutexRequest();
  504. if (g_fHttpClientInitialized == FALSE)
  505. {
  506. RpcStatus = InitializeHttpCommon();
  507. if (RpcStatus == RPC_S_OK)
  508. {
  509. RpcStatus = InitializeDefaultChannelLifetime();
  510. if (RpcStatus == RPC_S_OK)
  511. {
  512. RpcStatus = InitializeUseWinHttp();
  513. if (RpcStatus == RPC_S_OK)
  514. {
  515. RpcStatus = InitializeMinConnectionTimeout();
  516. if (RpcStatus == RPC_S_OK)
  517. {
  518. g_fHttpClientInitialized = TRUE;
  519. }
  520. }
  521. }
  522. }
  523. }
  524. else
  525. {
  526. RpcStatus = RPC_S_OK;
  527. }
  528. GlobalMutexClear();
  529. return RpcStatus;
  530. }
  531. RPC_STATUS InitializeHttpServer (
  532. void
  533. )
  534. /*++
  535. Routine Description:
  536. Initialize the Http server if not done already
  537. Arguments:
  538. Return Value:
  539. RPC_S_OK or RPC_S_* error
  540. --*/
  541. {
  542. RPC_STATUS RpcStatus;
  543. GlobalMutexRequest();
  544. if (g_fHttpServerInitialized == FALSE)
  545. {
  546. RpcStatus = InitializeHttpCommon();
  547. if (RpcStatus == RPC_S_OK)
  548. {
  549. RpcStatus = CookieCollection::InitializeServerCookieCollection();
  550. if (RpcStatus == RPC_S_OK)
  551. {
  552. g_fHttpServerInitialized = TRUE;
  553. }
  554. }
  555. }
  556. else
  557. {
  558. RpcStatus = RPC_S_OK;
  559. }
  560. GlobalMutexClear();
  561. return RpcStatus;
  562. }
  563. #if 1
  564. #define ShouldUseWinHttp(x) (TRUE)
  565. #else
  566. BOOL ShouldUseWinHttp (
  567. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials
  568. )
  569. /*++
  570. Routine Description:
  571. Based on http credentials determines whether WinHttp
  572. should be used or raw sockets.
  573. Arguments:
  574. HttpCredentials - transport credentials
  575. Return Value:
  576. non-zero - WinHttp should be used. 0 means it is not
  577. necessary to use WinHttp.
  578. --*/
  579. {
  580. RPC_STATUS RpcStatus;
  581. if (AlwaysUseWinHttp)
  582. return 1;
  583. if (HttpCredentials == NULL)
  584. return 0;
  585. if (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  586. return 1;
  587. if (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME)
  588. return 1;
  589. if (HttpCredentials->TransportCredentials)
  590. return 1;
  591. if (HttpCredentials->NumberOfAuthnSchemes)
  592. return 1;
  593. if (HttpCredentials->AuthnSchemes)
  594. return 1;
  595. if (HttpCredentials->ServerCertificateSubject)
  596. return 1;
  597. return 0;
  598. }
  599. #endif
  600. void CALLBACK HTTP2TimerCallback(
  601. PVOID lpParameter, // thread data
  602. BOOLEAN TimerOrWaitFired // reason
  603. )
  604. /*++
  605. Routine Description:
  606. A periodic timer fired. Reference it, and dispatch to
  607. the appropriate object.
  608. Arguments:
  609. lpParameter - the parameter supplied when the timer was
  610. registered. In our case the HTTP2PingOriginator object
  611. TimerOrWaitFired - the reason for the callback. Must be timer
  612. in our case.
  613. Return Value:
  614. RPC_S_OK or RPC_S_* error
  615. --*/
  616. {
  617. HTTP2PingOriginator *PingOriginator;
  618. RPC_STATUS RpcStatus;
  619. THREAD *Thread;
  620. ASSERT(TimerOrWaitFired);
  621. Thread = ThreadSelf();
  622. // if we can't initialize the thread object, we just return. Worst case
  623. // the connection will fall apart due to the timeout. That's ok.
  624. if (Thread == NULL)
  625. return;
  626. PingOriginator = (HTTP2PingOriginator *)lpParameter;
  627. RpcStatus = PingOriginator->ReferenceFromCallback();
  628. if (RpcStatus == RPC_S_OK)
  629. PingOriginator->TimerCallback();
  630. }
  631. void CALLBACK HTTP2TimeoutTimerCallback(
  632. PVOID lpParameter, // thread data
  633. BOOLEAN TimerOrWaitFired // reason
  634. )
  635. /*++
  636. Routine Description:
  637. A one time timer fired. Dispatch to
  638. the appropriate object.
  639. Arguments:
  640. lpParameter - the parameter supplied when the timer was
  641. registered. In our case the HTTP2TimeoutTargetConnection object
  642. TimerOrWaitFired - the reason for the callback. Must be timer
  643. in our case.
  644. Return Value:
  645. RPC_S_OK or RPC_S_* error
  646. --*/
  647. {
  648. HTTP2TimeoutTargetConnection *TimerTarget;
  649. RPC_STATUS RpcStatus;
  650. ASSERT(TimerOrWaitFired);
  651. // REVIEW - if this fails, offload to an RPC worker thread?
  652. ThreadSelf();
  653. TimerTarget = (HTTP2TimeoutTargetConnection *)lpParameter;
  654. TimerTarget->TimeoutExpired();
  655. }
  656. void CALLBACK WinHttpCallback (
  657. IN HINTERNET hInternet,
  658. IN DWORD_PTR dwContext,
  659. IN DWORD dwInternetStatus,
  660. IN LPVOID lpvStatusInformation OPTIONAL,
  661. IN DWORD dwStatusInformationLength
  662. )
  663. /*++
  664. Routine Description:
  665. The WinHttp callback routine.
  666. Arguments:
  667. hInternet - The hSession handle specified in a call to WinHttpSetStatusCallback.
  668. dwContext - Depends on the callback. May be the Context argument to WinHttpSendRequest
  669. dwInternetStatus - Status with which an async IO completed.
  670. lpvStatusInformation - Additional info depending on the callback.
  671. dwStatusInformationLength - Additional info depending on the callback.
  672. Return Value:
  673. --*/
  674. {
  675. HTTP2WinHttpTransportChannel *TransportChannel = (HTTP2WinHttpTransportChannel *) dwContext;
  676. WINHTTP_ASYNC_RESULT *AsyncResult;
  677. void *SendContext;
  678. BYTE *Buffer;
  679. RPC_STATUS RpcStatus;
  680. ULONG Api;
  681. BOOL HttpResult;
  682. ULONG StatusCode;
  683. ULONG StatusCodeLength;
  684. // WinHttp bug #541722 - bogus handles can be signalled if we do SSL through proxy. Ignore them
  685. if (dwContext == NULL)
  686. return;
  687. LOG_FN_OPERATION_ENTRY2(HTTP2LOG_OPERATION_WINHTTP_CALLBACK, HTTP2LOG_OT_WINHTTP_CALLBACK, TransportChannel, dwInternetStatus);
  688. // N.B. After setting the event or posting a runtime event, do not touch
  689. // the TransportChannel - it could be gone
  690. switch (dwInternetStatus)
  691. {
  692. case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
  693. if (TransportChannel->State == whtcsSendingRequest)
  694. TransportChannel->VerifyServerCredentials();
  695. break;
  696. case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
  697. ASSERT(TransportChannel->State == whtcsSendingRequest);
  698. // This signals the async completion of WinHttpSendRequest.
  699. TransportChannel->State = whtcsSentRequest;
  700. TransportChannel->AsyncError = RPC_S_OK;
  701. ASSERT(TransportChannel->SyncEvent);
  702. SetEvent(TransportChannel->SyncEvent);
  703. break;
  704. case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
  705. ASSERT(TransportChannel->State == whtcsReceivingResponse);
  706. // This signals the async completion of WinHttpReceiveResponse.
  707. TransportChannel->State = whtcsReceivedResponse;
  708. TransportChannel->AsyncError = RPC_S_OK;
  709. TransportChannel->DelayedReceive();
  710. break;
  711. case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
  712. ASSERT(TransportChannel->State == whtcsReceivedResponse);
  713. // This signals the async completion of WinHttpRead.
  714. ASSERT(TransportChannel->SyncEvent);
  715. SetEvent(TransportChannel->SyncEvent);
  716. break;
  717. case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
  718. if (TransportChannel->State == whtcsDraining)
  719. {
  720. TransportChannel->ContinueDrainChannel();
  721. }
  722. else
  723. {
  724. ASSERT(TransportChannel->State == whtcsReading);
  725. TransportChannel->State = whtcsReceivedResponse;
  726. // A read has completed asyncronously - issue a callback.
  727. TransportChannel->AsyncError = RPC_S_OK;
  728. // harvest the bytes available
  729. TransportChannel->NumberOfBytesTransferred = *(ULONG *)lpvStatusInformation;
  730. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  731. TransportChannel
  732. );
  733. }
  734. break;
  735. case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
  736. ASSERT(TransportChannel->State == whtcsWriting);
  737. TransportChannel->AsyncError = RPC_S_OK;
  738. // get the bytes written
  739. TransportChannel->NumberOfBytesTransferred = *(ULONG *)lpvStatusInformation;
  740. // A write has completed asyncronously - issue a callback.
  741. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  742. TransportChannel
  743. );
  744. break;
  745. case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
  746. // An async IO has failed. The async IO that can be outstanding is
  747. // from the following APIs:
  748. //
  749. // WinHttpSendRequest, WinHttpReceiveResponse, WinHttpReadData,
  750. // WinHttpWriteData.
  751. //
  752. // Conditions when async IO is outstanding for these APIs correpsond to the
  753. // states of: whtcsSendingRequest, whtcsReceivingResponse, whtcsReading,
  754. // whtcsWriting respectively.
  755. //
  756. // We are also notified of the failed API via dwResult field of WINHTTP_ASYNC_RESULT.
  757. //
  758. // WinHttpSendRequest and WinHttpReceiveResponse will wait for SyncEvent
  759. // to be raised. We will notify them of the failure by setting AsyncError.
  760. // WinHttpReadData and WinHttpWriteData failures will be propagated to the upper layers
  761. // via an async callback.
  762. //
  763. AsyncResult = (WINHTTP_ASYNC_RESULT *) lpvStatusInformation;
  764. Api = AsyncResult->dwResult;
  765. LOG_FN_OPERATION_ENTRY2(HTTP2LOG_OPERATION_WHTTP_ERROR, HTTP2LOG_OT_WINHTTP_CALLBACK, UlongToPtr(Api), AsyncResult->dwError);
  766. switch (Api)
  767. {
  768. case API_SEND_REQUEST:
  769. ASSERT(TransportChannel->State == whtcsSendingRequest);
  770. // the only two values allowed here are ok or access denied
  771. // (which means we didn't like the server certificate name).
  772. ASSERT((TransportChannel->AsyncError == RPC_S_OK)
  773. || (TransportChannel->AsyncError == RPC_S_INTERNAL_ERROR)
  774. || (TransportChannel->AsyncError == RPC_S_ACCESS_DENIED) );
  775. TransportChannel->State = whtcsSentRequest;
  776. VALIDATE(AsyncResult->dwError)
  777. {
  778. ERROR_WINHTTP_CANNOT_CONNECT,
  779. ERROR_WINHTTP_CONNECTION_ERROR,
  780. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  781. ERROR_WINHTTP_OUT_OF_HANDLES,
  782. ERROR_WINHTTP_REDIRECT_FAILED,
  783. ERROR_WINHTTP_RESEND_REQUEST,
  784. ERROR_WINHTTP_SECURE_FAILURE,
  785. ERROR_WINHTTP_SHUTDOWN,
  786. ERROR_WINHTTP_TIMEOUT,
  787. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  788. ERROR_NOT_ENOUGH_MEMORY,
  789. ERROR_WINHTTP_OPERATION_CANCELLED
  790. } END_VALIDATE;
  791. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  792. {
  793. ASSERT(0);
  794. }
  795. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  796. {
  797. ASSERT(TransportChannel->AsyncError == RPC_S_ACCESS_DENIED);
  798. }
  799. // if not access denied, make it send failed
  800. if (TransportChannel->AsyncError != RPC_S_ACCESS_DENIED)
  801. TransportChannel->AsyncError = RPC_P_SEND_FAILED;
  802. ASSERT(TransportChannel->SyncEvent);
  803. SetEvent(TransportChannel->SyncEvent);
  804. break;
  805. case API_RECEIVE_RESPONSE:
  806. ASSERT(TransportChannel->State == whtcsReceivingResponse);
  807. TransportChannel->State = whtcsReceivedResponse;
  808. VALIDATE(AsyncResult->dwError)
  809. {
  810. ERROR_WINHTTP_CANNOT_CONNECT,
  811. ERROR_WINHTTP_CONNECTION_ERROR,
  812. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  813. ERROR_WINHTTP_OUT_OF_HANDLES,
  814. ERROR_WINHTTP_REDIRECT_FAILED,
  815. ERROR_WINHTTP_RESEND_REQUEST,
  816. ERROR_WINHTTP_SECURE_FAILURE,
  817. ERROR_WINHTTP_SHUTDOWN,
  818. ERROR_WINHTTP_TIMEOUT,
  819. ERROR_WINHTTP_OPERATION_CANCELLED,
  820. ERROR_NOT_ENOUGH_MEMORY
  821. } END_VALIDATE;
  822. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  823. TransportChannel->AsyncError = RPC_P_AUTH_NEEDED;
  824. else
  825. TransportChannel->AsyncError = RPC_P_RECEIVE_FAILED;
  826. TransportChannel->DelayedReceive();
  827. break;
  828. case API_QUERY_DATA_AVAILABLE:
  829. // if we get closed while receiving data, we can be
  830. // in draining state
  831. ASSERT((TransportChannel->State == whtcsReading)
  832. || (TransportChannel->State == whtcsDraining));
  833. TransportChannel->State = whtcsReceivedResponse;
  834. VALIDATE(AsyncResult->dwError)
  835. {
  836. ERROR_WINHTTP_CANNOT_CONNECT,
  837. ERROR_WINHTTP_CONNECTION_ERROR,
  838. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  839. ERROR_WINHTTP_OUT_OF_HANDLES,
  840. ERROR_WINHTTP_REDIRECT_FAILED,
  841. ERROR_WINHTTP_RESEND_REQUEST,
  842. ERROR_WINHTTP_SECURE_FAILURE,
  843. ERROR_WINHTTP_SHUTDOWN,
  844. ERROR_WINHTTP_TIMEOUT,
  845. ERROR_WINHTTP_OPERATION_CANCELLED
  846. } END_VALIDATE;
  847. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  848. {
  849. ASSERT(0);
  850. }
  851. TransportChannel->AsyncError = RPC_P_RECEIVE_FAILED;
  852. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  853. TransportChannel
  854. );
  855. break;
  856. case API_WRITE_DATA:
  857. ASSERT(TransportChannel->State == whtcsWriting);
  858. VALIDATE(AsyncResult->dwError)
  859. {
  860. ERROR_WINHTTP_CANNOT_CONNECT,
  861. ERROR_WINHTTP_CONNECTION_ERROR,
  862. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  863. ERROR_WINHTTP_OUT_OF_HANDLES,
  864. ERROR_WINHTTP_REDIRECT_FAILED,
  865. ERROR_WINHTTP_RESEND_REQUEST,
  866. ERROR_WINHTTP_SECURE_FAILURE,
  867. ERROR_WINHTTP_SHUTDOWN,
  868. ERROR_WINHTTP_TIMEOUT,
  869. ERROR_WINHTTP_OPERATION_CANCELLED
  870. } END_VALIDATE;
  871. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  872. {
  873. ASSERT(0);
  874. }
  875. TransportChannel->AsyncError = RPC_P_SEND_FAILED;
  876. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  877. TransportChannel
  878. );
  879. break;
  880. default:
  881. ASSERT(0);
  882. }
  883. break;
  884. default:
  885. // don't care about the other notifications
  886. break;
  887. }
  888. LOG_FN_OPERATION_EXIT2(HTTP2LOG_OPERATION_WINHTTP_CALLBACK, HTTP2LOG_OT_WINHTTP_CALLBACK, TransportChannel, dwInternetStatus);
  889. };
  890. RPC_STATUS WaitForSyncSend (
  891. IN BASE_ASYNC_OBJECT *Connection,
  892. IN HTTP2SendContext *SendContext,
  893. IN HTTP2VirtualConnection *Parent,
  894. IN BOOL fDisableCancelCheck,
  895. IN ULONG Timeout
  896. )
  897. /*++
  898. Routine Description:
  899. Waits for a synchronous send to complete.
  900. Arguments:
  901. Connection - run time view of the transport connection
  902. SendContext - the send context
  903. Parent - the parent virtual connection (used to abort)
  904. fDisableCancelCheck - don't do checks for cancels. Can be
  905. used as optimization
  906. Timeout - the call timeout
  907. Return Value:
  908. RPC_S_OK or other RPC_S_* errors for error
  909. --*/
  910. {
  911. RPC_STATUS RpcStatus;
  912. HTTP2Channel *ThisChannel;
  913. // the IO was submitted. Wait for it.
  914. // If fDisableCancelCheck, make the thread wait non-alertably,
  915. // otherwise, make it wait alertably.
  916. RpcStatus = UTIL_GetOverlappedHTTP2ResultEx(Connection,
  917. &SendContext->Write.ol,
  918. SendContext->u.SyncEvent,
  919. !fDisableCancelCheck, // bAlertable
  920. Timeout);
  921. if (RpcStatus != RPC_S_OK)
  922. {
  923. Parent->AbortChannels(RpcStatus);
  924. if ((RpcStatus == RPC_S_CALL_CANCELLED) || (RpcStatus == RPC_P_TIMEOUT))
  925. {
  926. // Wait for the write to finish. Since we closed the
  927. // connection this won't take very long.
  928. UTIL_WaitForSyncHTTP2IO(&SendContext->Write.ol,
  929. SendContext->u.SyncEvent,
  930. FALSE, // fAlertable
  931. INFINITE // Timeout
  932. );
  933. }
  934. }
  935. return(RpcStatus);
  936. }
  937. void
  938. AddBufferQueueToChannel (
  939. IN LIST_ENTRY *NewBufferHead,
  940. IN HTTP2Channel *Channel
  941. )
  942. /*++
  943. Routine Description:
  944. Adds all the send contexts from the queue to the front of given channel.
  945. Presumably the channel has a plug channel down somewhere which does
  946. the actual ordering work
  947. Arguments:
  948. NewBufferHead - the list head of the buffer queue. They are assumed to
  949. be in order.
  950. Channel - the channel to make the sends on
  951. Return Value:
  952. Notes:
  953. The new channel must still be plugged.
  954. --*/
  955. {
  956. HTTP2SendContext *QueuedSendContext;
  957. LIST_ENTRY *CurrentListEntry;
  958. LIST_ENTRY *PrevListEntry;
  959. RPC_STATUS RpcStatus;
  960. // Queue the sends to the front of the new channel
  961. // walk the queue in reverse order and add it to the plug channel
  962. CurrentListEntry = NewBufferHead->Blink;
  963. while (CurrentListEntry != NewBufferHead)
  964. {
  965. QueuedSendContext
  966. = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  967. PrevListEntry = CurrentListEntry->Blink;
  968. QueuedSendContext->Flags = SendContextFlagPutInFront;
  969. RpcStatus = Channel->Send(QueuedSendContext);
  970. // since we know the channel is plugged yet, this cannot fail
  971. ASSERT(RpcStatus == RPC_S_OK);
  972. CurrentListEntry = PrevListEntry;
  973. }
  974. }
  975. void
  976. RPC_CLIENT_PROCESS_IDENTIFIER::SetHTTP2ClientIdentifier (
  977. IN void *Buffer,
  978. IN size_t BufferSize,
  979. IN BOOL fLocal
  980. )
  981. /*++
  982. Routine Description:
  983. sets an HTTP2 client identifier
  984. Arguments:
  985. Buffer - the buffer with the client identifier.
  986. BufferSize - the number of bytes containg valid
  987. info in the buffer.
  988. fLocal - non-zero if client is local. 0 otherwise.
  989. Return Value:
  990. --*/
  991. {
  992. BYTE *CurrentPosition;
  993. this->fLocal = fLocal;
  994. this->ZeroPadding = 0;
  995. RpcpMemorySet(u.ULongClientId, 0, sizeof(u.ULongClientId) - BufferSize);
  996. CurrentPosition = ((BYTE *)u.ULongClientId) + sizeof(u.ULongClientId) - BufferSize;
  997. RpcpMemoryCopy(CurrentPosition, Buffer, BufferSize);
  998. }
  999. RPC_STATUS
  1000. HttpSendIdentifyResponse(
  1001. IN SOCKET Socket
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. <TBS>
  1006. Arguments:
  1007. Socket -
  1008. Return Value:
  1009. None
  1010. --*/
  1011. {
  1012. RPC_STATUS Status = RPC_S_OK;
  1013. int iBytes;
  1014. char *pszId = HTTP_SERVER_ID_STR;
  1015. DWORD dwSize;
  1016. iBytes = send(
  1017. Socket,
  1018. pszId,
  1019. HTTP_SERVER_ID_STR_LEN,
  1020. 0
  1021. );
  1022. if (iBytes == SOCKET_ERROR)
  1023. {
  1024. VALIDATE(GetLastError())
  1025. {
  1026. WSAENETDOWN,
  1027. WSAECONNREFUSED,
  1028. WSAECONNRESET,
  1029. WSAENETRESET,
  1030. WSAETIMEDOUT
  1031. } END_VALIDATE;
  1032. Status = RPC_S_OUT_OF_RESOURCES;
  1033. }
  1034. return Status;
  1035. }
  1036. RPC_STATUS
  1037. HTTP_TryConnect( SOCKET Socket,
  1038. char *pszProxyMachine,
  1039. USHORT iPort )
  1040. /*++
  1041. Routine Description:
  1042. Used by HTTP_Open() to actually call the connect(). HTTP_Open() will try
  1043. first to reach the RPC Proxy directly, if it can't then it will call this
  1044. routine again to try to reach an HTTP proxy (i.e. MSProxy for example).
  1045. Arguments:
  1046. Socket - The socket to use in the connect().
  1047. pszProxyMachine - The name of the machine to try to connect() to.
  1048. iPort - The port to connect() on.
  1049. Return Value:
  1050. RPC_S_OK
  1051. RPC_S_OUT_OF_MEMORY
  1052. RPC_S_OUT_OF_RESOURCES
  1053. RPC_S_SERVER_UNAVAILABLE
  1054. RPC_S_INVALID_NET_ADDR
  1055. --*/
  1056. {
  1057. RPC_STATUS Status = RPC_S_OK;
  1058. WS_SOCKADDR ProxyServer;
  1059. RPC_CHAR pwszBuffer[MAX_HTTP_COMPUTERNAME_SIZE+1];
  1060. //
  1061. // Check for empty proxy machine name:
  1062. //
  1063. if ( (!pszProxyMachine) || (*pszProxyMachine == 0))
  1064. {
  1065. return RPC_S_SERVER_UNAVAILABLE;
  1066. }
  1067. memset((char *)&ProxyServer, 0, sizeof(ProxyServer));
  1068. //
  1069. // Resolve the machine name (or dot-notation address) into
  1070. // a network address. If that works then try to connect
  1071. // using the supplied port.
  1072. //
  1073. SimpleAnsiToPlatform(pszProxyMachine,pwszBuffer);
  1074. IP_ADDRESS_RESOLVER resolver(pwszBuffer,
  1075. cosClient,
  1076. ipvtuIPv4 // IP version to use
  1077. );
  1078. Status = resolver.NextAddress(&ProxyServer.inetaddr);
  1079. if (Status == RPC_S_OK)
  1080. {
  1081. ProxyServer.inetaddr.sin_family = AF_INET;
  1082. ProxyServer.inetaddr.sin_port = htons(iPort);
  1083. //
  1084. // Try to connect...
  1085. //
  1086. if (SOCKET_ERROR == connect(Socket,
  1087. (struct sockaddr *)&ProxyServer.inetaddr,
  1088. sizeof(ProxyServer.inetaddr)))
  1089. {
  1090. #if DBG_ERROR
  1091. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1092. DPFLTR_WARNING_LEVEL,
  1093. "HTTP_Open(): connect() failed: %d\n",
  1094. WSAGetLastError()));
  1095. #endif // DBG_ERROR
  1096. VALIDATE(GetLastError())
  1097. {
  1098. WSAENETDOWN,
  1099. WSAEADDRNOTAVAIL,
  1100. WSAECONNREFUSED,
  1101. WSAECONNABORTED,
  1102. WSAENETUNREACH,
  1103. WSAEHOSTUNREACH,
  1104. WSAENOBUFS,
  1105. WSAETIMEDOUT
  1106. } END_VALIDATE;
  1107. Status = RPC_S_SERVER_UNAVAILABLE;
  1108. }
  1109. }
  1110. return Status;
  1111. }
  1112. RPC_STATUS HTTP2Cookie::Create (
  1113. void
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Create a cryptographically strong HTTP2 cookie
  1118. Arguments:
  1119. Return Value:
  1120. RPC_S_OK or RPC_S_* failure
  1121. --*/
  1122. {
  1123. return GenerateRandomNumber(Cookie, sizeof(Cookie));
  1124. }
  1125. void HTTPResolverHint::VerifyInitialized (
  1126. void
  1127. )
  1128. /*++
  1129. Routine Description:
  1130. Verify that the resolver hint is properly initialized and consistent
  1131. Arguments:
  1132. Return Value:
  1133. --*/
  1134. {
  1135. ASSERT(RpcServer);
  1136. ASSERT(ServerPort != 0);
  1137. ASSERT(RpcProxy);
  1138. ASSERT(RpcProxyPort != 0);
  1139. if (HTTPProxy)
  1140. {
  1141. ASSERT(HTTPProxyPort != 0);
  1142. }
  1143. }
  1144. RPC_STATUS
  1145. RPC_ENTRY
  1146. HTTP_Initialize (
  1147. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1148. IN RPC_CHAR * /* NetworkAddress */,
  1149. IN RPC_CHAR * /* NetworkOptions */,
  1150. IN BOOL /* fAsync */
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Called by the runtime to do initial initialization of the transport
  1155. object. The purpose of this initialization is to allow the transport
  1156. to do some minimal initialization sufficient to ensure ordely
  1157. destruction in case of failure.
  1158. Arguments:
  1159. ThisConnection - an uninitialized connection allocated by the runtime
  1160. NetworkAddress - ignored
  1161. NetworkOptions - ignored
  1162. fAsync - ignored
  1163. Return Value:
  1164. RPC_S_OK for success of RPC_S_* / Win32 error for error.
  1165. --*/
  1166. {
  1167. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  1168. BaseObject->id = INVALID_PROTOCOL_ID;
  1169. return RPC_S_OK;
  1170. }
  1171. RPC_STATUS
  1172. RPC_ENTRY
  1173. HTTP_CheckIPAddressForDirectConnection (
  1174. IN HTTPResolverHint *Hint
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Checks if the rpc proxy server address given in the hint should be used
  1179. for direct connection based on registry settings
  1180. Arguments:
  1181. Hint - the resolver hint
  1182. Return Value:
  1183. RPC_S_OK or RPC_S_* / win32 error code
  1184. --*/
  1185. {
  1186. HKEY RpcOptionsKey;
  1187. DWORD Status;
  1188. DWORD KeyType;
  1189. const RPC_CHAR *UseProxyForIPAddrIfRDNSFailsRegKey = RPC_CONST_STRING("UseProxyForIPAddrIfRDNSFails");
  1190. const RPC_CHAR *RpcRegistryOptions =
  1191. RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  1192. DWORD UseProxyForIPAddrIfRDNSFails;
  1193. DWORD RegKeySize;
  1194. int err;
  1195. ADDRINFO AddrHint;
  1196. ADDRINFO *AddrInfo;
  1197. RpcpMemorySet(&AddrHint, 0, sizeof(ADDRINFO));
  1198. AddrHint.ai_flags = AI_NUMERICHOST;
  1199. err = getaddrinfo(Hint->RpcProxy,
  1200. NULL,
  1201. &AddrHint,
  1202. &AddrInfo
  1203. );
  1204. ASSERT((err != EAI_BADFLAGS)
  1205. && (err != EAI_SOCKTYPE));
  1206. if (err)
  1207. {
  1208. // the address was not numeric. It's not up to us to tell
  1209. // where this should go
  1210. return RPC_S_OK;
  1211. }
  1212. // assume direct connection for now
  1213. Hint->AccessType = rpcpatDirect;
  1214. Status = RegOpenKey( HKEY_LOCAL_MACHINE,
  1215. (const RPC_SCHAR *)RpcRegistryOptions,
  1216. &RpcOptionsKey );
  1217. if (Status != ERROR_SUCCESS)
  1218. {
  1219. // direct connection is already set
  1220. goto CleanupAndExit;
  1221. }
  1222. RegKeySize = sizeof(DWORD);
  1223. Status = RegQueryValueEx(RpcOptionsKey,
  1224. (const RPC_SCHAR *)UseProxyForIPAddrIfRDNSFailsRegKey,
  1225. NULL,
  1226. &KeyType,
  1227. (LPBYTE)&UseProxyForIPAddrIfRDNSFails,
  1228. &RegKeySize);
  1229. RegCloseKey(RpcOptionsKey);
  1230. if ( (Status != ERROR_SUCCESS) ||
  1231. (KeyType != REG_DWORD) )
  1232. {
  1233. // direct connection is already set
  1234. goto CleanupAndExit;
  1235. }
  1236. if (UseProxyForIPAddrIfRDNSFails != 1)
  1237. {
  1238. // direct connection is already set
  1239. goto CleanupAndExit;
  1240. }
  1241. err = getnameinfo(AddrInfo->ai_addr,
  1242. AddrInfo->ai_addrlen,
  1243. NULL,
  1244. 0,
  1245. NULL,
  1246. 0,
  1247. NI_NAMEREQD
  1248. );
  1249. if (err)
  1250. {
  1251. Hint->AccessType = rpcpatHTTPProxy;
  1252. }
  1253. // else
  1254. // direct connection is already set
  1255. CleanupAndExit:
  1256. freeaddrinfo(AddrInfo);
  1257. return RPC_S_OK;
  1258. }
  1259. void
  1260. RPC_ENTRY HTTP_FreeResolverHint (
  1261. IN void *ResolverHint
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. Called by the runtime to free the resolver hint.
  1266. Arguments:
  1267. ResolverHint - the resolver hint created by the transport.
  1268. Return Value:
  1269. --*/
  1270. {
  1271. HTTPResolverHint *Hint = (HTTPResolverHint *)ResolverHint;
  1272. Hint->FreeHTTPProxy();
  1273. Hint->FreeRpcProxy();
  1274. Hint->FreeRpcServer();
  1275. }
  1276. RPC_STATUS
  1277. RPC_ENTRY HTTP_CopyResolverHint (
  1278. IN void *TargetResolverHint,
  1279. IN void *SourceResolverHint,
  1280. IN BOOL SourceWillBeAbandoned
  1281. )
  1282. /*++
  1283. Routine Description:
  1284. Tells the transport to copy the resolver hint from Source to Target
  1285. Arguments:
  1286. TargetResolverHint - pointer to the target resolver hint
  1287. SourceResolverHint - pointer to the source resolver hint
  1288. SourceWillBeAbandoned - non-zero if the source hint was in temporary
  1289. location and will be abandoned. Zero otherwise.
  1290. Return Value:
  1291. if SourceWillBeAbandoned is specified, this function is guaranteed
  1292. to return RPC_S_OK. Otherwise, it may return RPC_S_OUT_OF_MEMORY as well.
  1293. --*/
  1294. {
  1295. HTTPResolverHint *TargetHint = (HTTPResolverHint *)TargetResolverHint;
  1296. HTTPResolverHint *SourceHint = (HTTPResolverHint *)SourceResolverHint;
  1297. ULONG HTTPProxyNameLength;
  1298. ASSERT(TargetHint != SourceHint);
  1299. // bulk copy most of the stuff, and then hand copy few items
  1300. RpcpMemoryCopy(TargetHint, SourceHint, sizeof(HTTPResolverHint));
  1301. if (SourceWillBeAbandoned)
  1302. {
  1303. // the source hint will be abandoned - just hijack all
  1304. // embedded pointers
  1305. if (SourceHint->RpcServer == SourceHint->RpcServerName)
  1306. TargetHint->RpcServer = TargetHint->RpcServerName;
  1307. SourceHint->HTTPProxy = NULL;
  1308. SourceHint->RpcProxy = NULL;
  1309. SourceHint->RpcServer = NULL;
  1310. }
  1311. else
  1312. {
  1313. TargetHint->HTTPProxy = NULL;
  1314. TargetHint->RpcProxy = NULL;
  1315. TargetHint->RpcServer = NULL;
  1316. if (SourceHint->HTTPProxy)
  1317. {
  1318. HTTPProxyNameLength = RpcpStringLengthA(SourceHint->HTTPProxy) + 1;
  1319. TargetHint->HTTPProxy = new char [HTTPProxyNameLength];
  1320. if (TargetHint->HTTPProxy == NULL)
  1321. goto FreeTargetHintAndExit;
  1322. RpcpMemoryCopy(TargetHint->HTTPProxy, SourceHint->HTTPProxy, HTTPProxyNameLength);
  1323. }
  1324. TargetHint->RpcProxy = new char [SourceHint->ProxyNameLength + 1];
  1325. if (TargetHint->RpcProxy == NULL)
  1326. goto FreeTargetHintAndExit;
  1327. RpcpMemoryCopy(TargetHint->RpcProxy, SourceHint->RpcProxy, SourceHint->ProxyNameLength + 1);
  1328. if (SourceHint->RpcServer == SourceHint->RpcServerName)
  1329. TargetHint->RpcServer = TargetHint->RpcServerName;
  1330. else
  1331. {
  1332. TargetHint->RpcServer = new char [SourceHint->ServerNameLength + 1];
  1333. if (TargetHint->RpcServer == NULL)
  1334. goto FreeTargetHintAndExit;
  1335. RpcpMemoryCopy(TargetHint->RpcServer, SourceHint->RpcServer, SourceHint->ServerNameLength + 1);
  1336. }
  1337. }
  1338. return RPC_S_OK;
  1339. FreeTargetHintAndExit:
  1340. TargetHint->FreeHTTPProxy();
  1341. TargetHint->FreeRpcProxy();
  1342. TargetHint->FreeRpcServer();
  1343. return RPC_S_OUT_OF_MEMORY;
  1344. }
  1345. int
  1346. RPC_ENTRY HTTP_CompareResolverHint (
  1347. IN void *ResolverHint1,
  1348. IN void *ResolverHint2
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. Tells the transport to compare the given 2 resolver hints
  1353. Arguments:
  1354. ResolverHint1 - pointer to the first resolver hint
  1355. ResolverHint2 - pointer to the second resolver hint
  1356. Return Value:
  1357. (same semantics as memcmp)
  1358. 0 - the resolver hints are equal
  1359. non-zero - the resolver hints are not equal
  1360. --*/
  1361. {
  1362. HTTPResolverHint *Hint1 = (HTTPResolverHint *)ResolverHint1;
  1363. HTTPResolverHint *Hint2 = (HTTPResolverHint *)ResolverHint2;
  1364. if (Hint1->Version != Hint2->Version)
  1365. return 1;
  1366. if (Hint1->ServerPort != Hint2->ServerPort)
  1367. return 1;
  1368. if (Hint1->ServerNameLength != Hint2->ServerNameLength)
  1369. return 1;
  1370. return RpcpMemoryCompare(Hint1->RpcServer, Hint2->RpcServer, Hint1->ServerNameLength);
  1371. }
  1372. RPC_STATUS RPC_ENTRY
  1373. HTTP_SetLastBufferToFree (
  1374. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1375. IN void *Buffer
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. Tells the transport what buffer to free when it is done with the last send
  1380. Arguments:
  1381. ThisConnection - connection to act on.
  1382. Buffer - pointer of the buffer to free. Must be freed using
  1383. RpcFreeBuffer/I_RpcTransConnectionFreePacket
  1384. Return Value:
  1385. RPC_S_OK - the last buffer to free was accepted by the transport
  1386. RPC_S_CANNOT_SUPPORT - the transport does not support this functionality
  1387. --*/
  1388. {
  1389. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  1390. HTTP2ServerVirtualConnection *VirtualConnection;
  1391. RPC_STATUS RpcStatus;
  1392. if (BaseObject->id == HTTPv2)
  1393. {
  1394. // this must be called on server connections only
  1395. ASSERT(BaseObject->type == (COMPLEX_T | CONNECTION | SERVER));
  1396. VirtualConnection = (HTTP2ServerVirtualConnection *) ThisConnection;
  1397. VirtualConnection->SetLastBufferToFree(Buffer);
  1398. return RPC_S_OK;
  1399. }
  1400. else
  1401. {
  1402. return RPC_S_CANNOT_SUPPORT;
  1403. }
  1404. }
  1405. RPC_STATUS
  1406. RPC_ENTRY
  1407. HTTP_Open (
  1408. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1409. IN RPC_CHAR * ProtocolSequence,
  1410. IN RPC_CHAR * NetworkAddress,
  1411. IN RPC_CHAR * Endpoint,
  1412. IN RPC_CHAR * NetworkOptions,
  1413. IN UINT ConnTimeout,
  1414. IN UINT SendBufferSize,
  1415. IN UINT RecvBufferSize,
  1416. IN PVOID ResolverHint,
  1417. IN BOOL fHintInitialized,
  1418. IN ULONG CallTimeout,
  1419. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  1420. IN void *AdditionalCredentials OPTIONAL
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. Opens a connection to a server.
  1425. Arguments:
  1426. ThisConnection - A place to store the connection
  1427. ProtocolSeqeunce - "ncacn_http"
  1428. NetworkAddress - The name of the server, either a dot address or DNS name
  1429. NetworkOptions - the http binding handle options (e.g. HttpProxy/RpcProxy)
  1430. ConnTimeout - See RpcMgmtSetComTimeout
  1431. 0 - Min
  1432. 5 - Default
  1433. 9 - Max
  1434. 10 - Infinite
  1435. SendBufferSize - ignored
  1436. RecvBufferSize - ignored
  1437. ResolverHint - pointer to the resolver hint object
  1438. fHintInitialized - non-zero if the ResolverHint points to previously
  1439. initialized memory. 0 otheriwse.
  1440. CallTimeout - call timeout in milliseconds
  1441. AdditionalTransportCredentialsType - the type of additional credentials that we were
  1442. given
  1443. AdditionalCredentials - additional credentials that we were given.
  1444. Return Value:
  1445. RPC_S_OK
  1446. RPC_S_OUT_OF_MEMORY
  1447. RPC_S_OUT_OF_RESOURCES
  1448. RPC_S_SERVER_UNAVAILABLE
  1449. RPC_S_INVALID_ENDPOINT_FORMAT
  1450. RPC_S_INVALID_NET_ADDR
  1451. --*/
  1452. {
  1453. HTTPResolverHint *Hint = (HTTPResolverHint *)ResolverHint;
  1454. char *RpcProxyPort = NULL;
  1455. char *HttpProxyPort = NULL;
  1456. BOOL NetworkAddressAllocated;
  1457. BOOL Result;
  1458. char PortString[20];
  1459. ULONG StringLength;
  1460. RPC_STATUS Status;
  1461. RPC_STATUS RetValue;
  1462. PWS_CCONNECTION p = (PWS_CCONNECTION) ThisConnection;
  1463. HTTP2ClientVirtualConnection *VirtualConnection = (HTTP2ClientVirtualConnection *) ThisConnection;
  1464. BOOL Retry;
  1465. BOOL fUserModeConnection;
  1466. BOOL HintNeedsCleanup;
  1467. RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;
  1468. BOOL UseSSLPort;
  1469. ULONG HostAddr;
  1470. BOOL LocalDirect;
  1471. ASSERT(NetworkAddress);
  1472. ASSERT(Endpoint);
  1473. ASSERT(RpcpStringCompare(ProtocolSequence, L"ncacn_http") == 0);
  1474. if (AdditionalTransportCredentialsType != 0)
  1475. {
  1476. if (AdditionalTransportCredentialsType != RPC_C_AUTHN_INFO_TYPE_HTTP)
  1477. {
  1478. ASSERT(0);
  1479. return RPC_S_CANNOT_SUPPORT;
  1480. }
  1481. ASSERT(AdditionalCredentials != NULL);
  1482. }
  1483. HttpCredentials = (RPC_HTTP_TRANSPORT_CREDENTIALS_W *) AdditionalCredentials;
  1484. Status = InitializeHttpClientIfNecessary();
  1485. if (Status != RPC_S_OK)
  1486. return Status;
  1487. HintNeedsCleanup = FALSE;
  1488. // Check the resolver hint. If not initialized, initialize all
  1489. // fields in the hint
  1490. if (fHintInitialized == FALSE)
  1491. {
  1492. RpcProxyPort = NULL;
  1493. HttpProxyPort = NULL;
  1494. Hint->HTTPProxy = NULL;
  1495. Hint->RpcProxy = NULL;
  1496. Hint->RpcServer = NULL;
  1497. Status = Hint->AssociationGroupId.Create();
  1498. if (Status != RPC_S_OK)
  1499. {
  1500. RetValue = Status;
  1501. goto AbortAndCleanup;
  1502. }
  1503. // the TCP transport should have been initialized by now
  1504. ASSERT(HTTPTransInfo);
  1505. Status = HTTPTransInfo->StartServerIfNecessary();
  1506. if (Status != RPC_S_OK)
  1507. {
  1508. RetValue = Status;
  1509. goto AbortAndCleanup;
  1510. }
  1511. StringLength = RpcpStringLength(NetworkAddress);
  1512. //
  1513. // RPC Server Name
  1514. //
  1515. if (StringLength == 0)
  1516. {
  1517. // no server name was specified. Use local machine name
  1518. NetworkAddress = AllocateAndGetComputerName(cnaNew,
  1519. ComputerNamePhysicalDnsFullyQualified,
  1520. 0, // ExtraBytes
  1521. 0, // Starting offset
  1522. &StringLength
  1523. );
  1524. if (NetworkAddress == NULL)
  1525. return RPC_S_OUT_OF_MEMORY;
  1526. NetworkAddressAllocated = TRUE;
  1527. }
  1528. else
  1529. {
  1530. // make space for terminating NULL
  1531. StringLength += 1;
  1532. NetworkAddressAllocated = FALSE;
  1533. }
  1534. // StringLength is in characters and includes terminating null
  1535. if (StringLength <= sizeof(Hint->RpcServerName))
  1536. {
  1537. Hint->RpcServer = Hint->RpcServerName;
  1538. LogEvent(SU_HTTPv2, EV_SET, &Hint->RpcServer, Hint->RpcServer, 0, 1, 0);
  1539. }
  1540. else
  1541. {
  1542. Hint->RpcServer = new char [StringLength];
  1543. LogEvent(SU_HTTPv2, EV_SET, &Hint->RpcServer, Hint->RpcServer, 1, 1, 0);
  1544. if (Hint->RpcServer == NULL)
  1545. {
  1546. if (NetworkAddressAllocated)
  1547. delete NetworkAddress;
  1548. return RPC_S_OUT_OF_MEMORY;
  1549. }
  1550. }
  1551. SimplePlatformToAnsi(NetworkAddress, Hint->RpcServer);
  1552. // subtract 1 to eliminate terminating NULL
  1553. Hint->ServerNameLength = StringLength - 1;
  1554. if (NetworkAddressAllocated)
  1555. {
  1556. delete NetworkAddress;
  1557. NetworkAddress = NULL;
  1558. }
  1559. // by now Hint->RpcServer points to the ascii name for the server
  1560. ASSERT(Hint->RpcServer);
  1561. //
  1562. // At this point, we know the destination server/port, but don't yet know
  1563. // if we need to go through an HTTP proxy, and what the IIS RPC proxy
  1564. // machine is. We'll get these, if specified from the network options
  1565. // and the registry.
  1566. //
  1567. if (HttpCredentials && (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL))
  1568. UseSSLPort = TRUE;
  1569. else
  1570. UseSSLPort = FALSE;
  1571. Result = HttpParseNetworkOptions(
  1572. NetworkOptions,
  1573. Hint->RpcServer,
  1574. &(Hint->RpcProxy),
  1575. &RpcProxyPort,
  1576. UseSSLPort,
  1577. &(Hint->HTTPProxy),
  1578. &HttpProxyPort,
  1579. &(Hint->AccessType),
  1580. (unsigned long *) &Status
  1581. );
  1582. if (Result == FALSE)
  1583. {
  1584. ASSERT(Status != RPC_S_OK);
  1585. Hint->FreeRpcServer();
  1586. return Status;
  1587. }
  1588. else
  1589. {
  1590. if (Hint->AccessType != rpcpatDirect)
  1591. {
  1592. ASSERT(Hint->HTTPProxy);
  1593. // if the proxy name is empty, set the method to direct
  1594. if (Hint->HTTPProxy[0] == 0)
  1595. Hint->AccessType = rpcpatDirect;
  1596. }
  1597. ASSERT(Status == RPC_S_OK);
  1598. HintNeedsCleanup = TRUE;
  1599. }
  1600. Status = EndpointToPortNumber(Endpoint, Hint->ServerPort);
  1601. if (Status != RPC_S_OK)
  1602. {
  1603. RetValue = Status;
  1604. goto AbortAndCleanup;
  1605. }
  1606. Status = EndpointToPortNumberA(RpcProxyPort, Hint->RpcProxyPort);
  1607. if (Status != RPC_S_OK)
  1608. {
  1609. RetValue = Status;
  1610. goto AbortAndCleanup;
  1611. }
  1612. Hint->ProxyNameLength = RpcpStringLengthA(Hint->RpcProxy);
  1613. if (Hint->HTTPProxy)
  1614. {
  1615. Status = EndpointToPortNumberA(HttpProxyPort, Hint->HTTPProxyPort);
  1616. if (Status != RPC_S_OK)
  1617. {
  1618. RetValue = Status;
  1619. goto AbortAndCleanup;
  1620. }
  1621. }
  1622. // we will optimistically presume that we can talk HTTP2
  1623. // until proven wrong
  1624. Hint->Version = httpvHTTP2;
  1625. // by now the resolver hint is fully initialized. fall through
  1626. // the case that has initialized resolver hint
  1627. }
  1628. Hint->VerifyInitialized();
  1629. // disable retries by default. If we have to loop around, we will set it to TRUE
  1630. Retry = FALSE;
  1631. do
  1632. {
  1633. // we have it all now.
  1634. if (Hint->Version == httpvHTTP2)
  1635. {
  1636. // use explicit placement
  1637. VirtualConnection = new (ThisConnection) HTTP2ClientVirtualConnection (
  1638. (RPC_HTTP_TRANSPORT_CREDENTIALS *)AdditionalCredentials,
  1639. &Status);
  1640. if (Status != RPC_S_OK)
  1641. {
  1642. VirtualConnection->HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  1643. RetValue = Status;
  1644. goto AbortAndCleanup;
  1645. }
  1646. Status = VirtualConnection->ClientOpen(Hint,
  1647. fHintInitialized,
  1648. ConnTimeout,
  1649. CallTimeout
  1650. );
  1651. // if we got a protocol error or a receive failed, and
  1652. // we don't have credentials, fall back to old protocol.
  1653. if (
  1654. (
  1655. (Status == RPC_S_PROTOCOL_ERROR)
  1656. ||
  1657. (Status == RPC_P_RECEIVE_FAILED)
  1658. )
  1659. &&
  1660. (HttpCredentials == NULL)
  1661. )
  1662. {
  1663. // cause the loop to start over.
  1664. // make sure next iteration it tries old http
  1665. Hint->Version = httpvHTTP;
  1666. Retry = TRUE;
  1667. }
  1668. else
  1669. {
  1670. if ((Status == RPC_S_PROTOCOL_ERROR)
  1671. ||
  1672. (Status == RPC_P_RECEIVE_FAILED))
  1673. {
  1674. Status = RPC_S_SERVER_UNAVAILABLE;
  1675. }
  1676. ASSERT(Status != RPC_P_PACKET_CONSUMED);
  1677. RetValue = Status;
  1678. VirtualConnection->id = HTTPv2;
  1679. if (Status == RPC_S_OK)
  1680. goto CleanupAndExit;
  1681. else
  1682. goto AbortAndCleanup;
  1683. }
  1684. }
  1685. else
  1686. {
  1687. ASSERT(Hint->Version == httpvHTTP);
  1688. // HTTP1 doesn't support proxy discovery. If we don't know
  1689. // just assume local and hope it works.
  1690. if (Hint->AccessType == rpcpatUnknown)
  1691. Hint->AccessType = rpcpatDirect;
  1692. // we need to re-initialize the connection object with old
  1693. // format connection
  1694. WS_Initialize(p, 0, 0, 0);
  1695. // use explicit placement to initialize the vtable. We need this to
  1696. // be able to use the virtual functions
  1697. p = new (p) WS_CLIENT_CONNECTION;
  1698. p->id = HTTP;
  1699. // Call common open function. Note that for http connection
  1700. // WS_Open will just open a socket. That's all we need right now.
  1701. Status = WS_Open(p,
  1702. NULL,
  1703. ConnTimeout,
  1704. SendBufferSize,
  1705. RecvBufferSize,
  1706. CallTimeout,
  1707. FALSE // fHTTP2Open
  1708. );
  1709. if (Status != RPC_S_OK)
  1710. {
  1711. RetValue = Status;
  1712. goto AbortAndCleanup;
  1713. }
  1714. //
  1715. // WS_Open has been successfully called. Do connect() work here...
  1716. //
  1717. // If AccessType is direct, then we are going to try to directly
  1718. // connect to the IIS that is the RPC Proxy first. If that suceeds,
  1719. // then we will just tunnel to the RPC server from there. If it fails,
  1720. // then we will try to go through an HTTP proxy (i.e. MSProxy server)
  1721. // if one is available...
  1722. if (Hint->AccessType != rpcpatHTTPProxy)
  1723. {
  1724. Status = HTTP_CheckIPAddressForDirectConnection(Hint);
  1725. if (Status != RPC_S_OK)
  1726. {
  1727. RetValue = RPC_S_OUT_OF_MEMORY;
  1728. goto AbortAndCleanup;
  1729. }
  1730. if (Hint->AccessType == rpcpatDirect)
  1731. {
  1732. Status = HTTP_TryConnect( p->Conn.Socket, Hint->RpcProxy, Hint->RpcProxyPort );
  1733. }
  1734. }
  1735. if ((Status != RPC_S_OK) || (Hint->AccessType != rpcpatDirect))
  1736. {
  1737. //
  1738. // If we get here, then we are going to try to use an HTTP proxy first...
  1739. //
  1740. Status = HTTP_TryConnect( p->Conn.Socket, Hint->HTTPProxy, Hint->HTTPProxyPort );
  1741. //
  1742. // If we successfully connected to the HTTP proxy, then let's go on and
  1743. // tunnel through to the RPC proxy:
  1744. //
  1745. if (Status != RPC_S_OK)
  1746. {
  1747. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1748. goto Abort;
  1749. }
  1750. PortNumberToEndpointA(Hint->RpcProxyPort, PortString);
  1751. if (!HttpTunnelToRpcProxy(p->Conn.Socket,
  1752. Hint->RpcProxy,
  1753. PortString))
  1754. {
  1755. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1756. goto Abort;
  1757. }
  1758. }
  1759. //
  1760. // Finally, negotiate with the RPC proxy to get the connection through to
  1761. // the RPC server.
  1762. //
  1763. PortNumberToEndpointA(Hint->ServerPort, PortString);
  1764. if (!HttpTunnelToRpcServer( p->Conn.Socket,
  1765. Hint->RpcServer,
  1766. PortString ))
  1767. {
  1768. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1769. goto Abort;
  1770. }
  1771. fUserModeConnection = IsUserModeSocket(p->Conn.Socket, &RetValue);
  1772. if (RetValue != RPC_S_OK)
  1773. goto Abort;
  1774. // if this is SAN or loadable transport not using true handles, go through Winsock
  1775. if (fUserModeConnection)
  1776. p = new (p) WS_SAN_CLIENT_CONNECTION;
  1777. Retry = FALSE;
  1778. }
  1779. }
  1780. while (Retry);
  1781. RetValue = RPC_S_OK;
  1782. goto CleanupAndExit;
  1783. Abort:
  1784. p->WS_CONNECTION::Abort();
  1785. AbortAndCleanup:
  1786. if (HintNeedsCleanup)
  1787. {
  1788. ASSERT(RetValue != RPC_S_OK);
  1789. Hint->FreeRpcServer();
  1790. Hint->FreeRpcProxy();
  1791. Hint->FreeHTTPProxy();
  1792. }
  1793. CleanupAndExit:
  1794. VALIDATE (RetValue)
  1795. {
  1796. RPC_S_OK,
  1797. RPC_S_PROTSEQ_NOT_SUPPORTED,
  1798. RPC_S_SERVER_UNAVAILABLE,
  1799. RPC_S_OUT_OF_MEMORY,
  1800. RPC_S_OUT_OF_RESOURCES,
  1801. RPC_S_SERVER_TOO_BUSY,
  1802. RPC_S_INVALID_NETWORK_OPTIONS,
  1803. RPC_S_INVALID_ENDPOINT_FORMAT,
  1804. RPC_S_INVALID_NET_ADDR,
  1805. RPC_S_ACCESS_DENIED,
  1806. RPC_S_INTERNAL_ERROR,
  1807. RPC_S_SERVER_OUT_OF_MEMORY,
  1808. RPC_S_CALL_CANCELLED
  1809. } END_VALIDATE;
  1810. if (RpcProxyPort != NULL)
  1811. delete RpcProxyPort;
  1812. if (HttpProxyPort != NULL)
  1813. delete HttpProxyPort;
  1814. if (Hint->ServerNameLength <= sizeof(Hint->RpcServerName))
  1815. {
  1816. ASSERT(Hint->RpcServer == Hint->RpcServerName);
  1817. }
  1818. return (RetValue);
  1819. }
  1820. RPC_STATUS
  1821. HTTP_ServerListen(
  1822. IN RPC_TRANSPORT_ADDRESS ThisAddress,
  1823. IN RPC_CHAR *NetworkAddress,
  1824. IN OUT RPC_CHAR * *pEndpoint,
  1825. IN UINT PendingQueueSize,
  1826. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1827. IN ULONG EndpointFlags,
  1828. IN ULONG NICFlags,
  1829. OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
  1830. )
  1831. {
  1832. RPC_STATUS RpcStatus;
  1833. RpcStatus = InitializeHttpServerIfNecessary();
  1834. if (RpcStatus != RPC_S_OK)
  1835. return RpcStatus;
  1836. return (TCP_ServerListenEx(
  1837. ThisAddress,
  1838. NetworkAddress,
  1839. pEndpoint,
  1840. PendingQueueSize,
  1841. SecurityDescriptor,
  1842. EndpointFlags,
  1843. NICFlags,
  1844. TRUE, // HTTP!
  1845. ppAddressVector
  1846. ));
  1847. }
  1848. void WINAPI ProxyIoCompletionCallback (
  1849. IN LPEXTENSION_CONTROL_BLOCK lpECB,
  1850. IN PVOID pContext,
  1851. IN DWORD cbIO,
  1852. IN DWORD dwError
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. IIS io completion callback function
  1857. Arguments:
  1858. lpECB - extension control block
  1859. pContext - the IISChannel pointer.
  1860. cbIO - Bytes transferred in the last operation
  1861. dwError - status of the operation
  1862. Return Value:
  1863. --*/
  1864. {
  1865. HTTP2IISTransportChannel *IISChannel;
  1866. THREAD *Thread;
  1867. Thread = ThreadSelf();
  1868. if (Thread == NULL)
  1869. return; // abandon the completion if worse comes to worse.
  1870. IISChannel = (HTTP2IISTransportChannel *)pContext;
  1871. IISChannel->IOCompleted(cbIO, dwError);
  1872. }
  1873. BOOL RPCTransInitialized = FALSE;
  1874. RPCRTAPI
  1875. RPC_STATUS
  1876. RPC_ENTRY
  1877. I_RpcProxyNewConnection (
  1878. IN ULONG ConnectionType,
  1879. IN USHORT *ServerAddress,
  1880. IN USHORT *ServerPort,
  1881. IN void *ConnectionParameter,
  1882. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface
  1883. )
  1884. /*++
  1885. Routine Description:
  1886. Entry point from the ISAPI extension. Called when a new
  1887. connection request arrives at an in or out proxy.
  1888. Arguments:
  1889. ConnectionType - currently RPC_PROXY_CONNECTION_TYPE_IN_PROXY or
  1890. RPC_PROXY_CONNECTION_TYPE_OUT_PROXY to indicate the type of
  1891. connection establishment request we have received
  1892. ServerAddress - unicode network address of the server
  1893. ServerPort - unicode port of the server
  1894. ConnectionParameter - the Extension Control Block in this case.
  1895. ProxyCallbackInterface - a callback interface to the proxy to perform
  1896. various proxy specific functions
  1897. Return Value:
  1898. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  1899. --*/
  1900. {
  1901. RPC_STATUS RpcStatus = RPC_S_OK;
  1902. EXTENSION_CONTROL_BLOCK *ECB;
  1903. void *IISContext;
  1904. BOOL Result;
  1905. RPC_TRANSPORT_INTERFACE TransInterface;
  1906. TRANS_INFO *TransInfo;
  1907. THREAD *ThisThread;
  1908. HTTP2ProxyVirtualConnection *ProxyVirtualConnection;
  1909. if (RPCTransInitialized == FALSE)
  1910. {
  1911. InitializeIfNecessary();
  1912. GlobalMutexRequest();
  1913. // all of the initialization here is idempotent.
  1914. // If we fail midway, we don't have to un-initialize -
  1915. // next initialization attempt will pick up where we left.
  1916. RpcStatus = OsfMapRpcProtocolSequence(FALSE,
  1917. L"ncacn_http",
  1918. &TransInfo);
  1919. if (RpcStatus == RPC_S_OK)
  1920. {
  1921. ASSERT(TransInfo);
  1922. if (HTTPTransInfo == NULL)
  1923. HTTPTransInfo = TransInfo;
  1924. RpcStatus = TransInfo->StartServerIfNecessary();
  1925. if (RpcStatus == RPC_S_OK)
  1926. {
  1927. RpcStatus = InitializeDefaultChannelLifetime();
  1928. if (RpcStatus == RPC_S_OK)
  1929. {
  1930. RpcStatus = InitializeActAsWebFarm();
  1931. if (RpcStatus == RPC_S_OK)
  1932. {
  1933. RpcStatus = InitializeMinConnectionTimeout();
  1934. if (RpcStatus == RPC_S_OK)
  1935. {
  1936. RpcStatus = CookieCollection::InitializeInProxyCookieCollection();
  1937. if (RpcStatus == RPC_S_OK)
  1938. {
  1939. RpcStatus = CookieCollection::InitializeOutProxyCookieCollection();
  1940. if (RpcStatus == RPC_S_OK)
  1941. {
  1942. RpcStatus = InitializeReceiveWindows();
  1943. }
  1944. }
  1945. }
  1946. }
  1947. }
  1948. }
  1949. }
  1950. RPCTransInitialized = (RpcStatus == RPC_S_OK);
  1951. GlobalMutexClear();
  1952. if (RpcStatus != RPC_S_OK)
  1953. {
  1954. return RPC_S_OK;
  1955. }
  1956. }
  1957. ThisThread = ThreadSelf();
  1958. if (ThisThread == NULL)
  1959. return RPC_S_OUT_OF_MEMORY;
  1960. if (ConnectionType == RPC_PROXY_CONNECTION_TYPE_IN_PROXY)
  1961. {
  1962. ProxyVirtualConnection = new HTTP2InProxyVirtualConnection(&RpcStatus);
  1963. }
  1964. else
  1965. {
  1966. ASSERT(ConnectionType == RPC_PROXY_CONNECTION_TYPE_OUT_PROXY);
  1967. ProxyVirtualConnection = new HTTP2OutProxyVirtualConnection(&RpcStatus);
  1968. }
  1969. if (ProxyVirtualConnection == NULL)
  1970. return RPC_S_OUT_OF_MEMORY;
  1971. if (RpcStatus != RPC_S_OK)
  1972. {
  1973. delete ProxyVirtualConnection;
  1974. return RpcStatus;
  1975. }
  1976. RpcStatus = ProxyVirtualConnection->InitializeProxyFirstLeg(ServerAddress,
  1977. ServerPort,
  1978. ConnectionParameter,
  1979. ProxyCallbackInterface,
  1980. &IISContext
  1981. );
  1982. if (RpcStatus != RPC_S_OK)
  1983. {
  1984. delete ProxyVirtualConnection;
  1985. return RpcStatus;
  1986. }
  1987. // we have initialized far enough. Associate callback
  1988. // with this connection
  1989. ECB = (EXTENSION_CONTROL_BLOCK *) ConnectionParameter;
  1990. Result = ECB->ServerSupportFunction (ECB->ConnID,
  1991. HSE_REQ_IO_COMPLETION,
  1992. ProxyIoCompletionCallback,
  1993. NULL,
  1994. (LPDWORD)IISContext
  1995. );
  1996. if (Result == FALSE)
  1997. {
  1998. ProxyVirtualConnection->Abort();
  1999. return RPC_S_OUT_OF_MEMORY;
  2000. }
  2001. RpcStatus = ProxyVirtualConnection->StartProxy();
  2002. if (RpcStatus != RPC_S_OK)
  2003. {
  2004. ProxyVirtualConnection->Abort();
  2005. // fall through to the end of the function
  2006. }
  2007. return RpcStatus;
  2008. }
  2009. RPCRTAPI
  2010. RPC_STATUS
  2011. RPC_ENTRY
  2012. HTTP2IISDirectReceive (
  2013. IN void *Context
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. Direct notification from the thread pool to an IIS channel
  2018. for a receive. The proxy stacks use that to post receives
  2019. to themselves.
  2020. Arguments:
  2021. Context - the HTTP2IISTransportChannel
  2022. Return Value:
  2023. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2024. --*/
  2025. {
  2026. ((HTTP2IISTransportChannel *)Context)->DirectReceive();
  2027. return RPC_S_OK;
  2028. }
  2029. RPCRTAPI
  2030. RPC_STATUS
  2031. RPC_ENTRY
  2032. HTTP2DirectReceive (
  2033. IN void *Context,
  2034. OUT BYTE **ReceivedBuffer,
  2035. OUT ULONG *ReceivedBufferLength,
  2036. OUT void **RuntimeConnection,
  2037. OUT BOOL *IsServer
  2038. )
  2039. /*++
  2040. Routine Description:
  2041. Direct notification from the thread pool to a receiver
  2042. for a receive. The stacks use that to post receives
  2043. to themselves.
  2044. Arguments:
  2045. Context - an instance of the HTTP2EndpointReceiver
  2046. ReceivedBuffer - the buffer that we received.
  2047. ReceivedBufferLength - the length of the received
  2048. buffer
  2049. RuntimeConnection - the connection to return to the runtime
  2050. if the packet is not consumed.
  2051. IsServer - true if this is the server
  2052. Return Value:
  2053. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2054. --*/
  2055. {
  2056. RPC_STATUS RpcStatus;
  2057. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_RECV_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2058. RpcStatus = ((HTTP2EndpointReceiver *)Context)->DirectReceiveComplete(
  2059. ReceivedBuffer,
  2060. ReceivedBufferLength,
  2061. RuntimeConnection,
  2062. IsServer
  2063. );
  2064. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_RECV_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2065. return RpcStatus;
  2066. }
  2067. RPCRTAPI
  2068. RPC_STATUS
  2069. RPC_ENTRY
  2070. HTTP2WinHttpDirectReceive (
  2071. IN void *Context,
  2072. OUT BYTE **ReceivedBuffer,
  2073. OUT ULONG *ReceivedBufferLength,
  2074. OUT void **RuntimeConnection
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. Direct notification from the thread pool to a receiver
  2079. for a receive. The stacks use that to post receives
  2080. to themselves.
  2081. Arguments:
  2082. Context - an instance of HTTP2WinHttpTransportChannel
  2083. ReceivedBuffer - the buffer that we received.
  2084. ReceivedBufferLength - the length of the received
  2085. buffer
  2086. RuntimeConnection - the connection to return to the runtime
  2087. if the packet is not consumed.
  2088. Return Value:
  2089. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2090. --*/
  2091. {
  2092. RPC_STATUS RpcStatus;
  2093. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DRECV_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2094. RpcStatus = ((HTTP2WinHttpTransportChannel *)Context)->DirectReceiveComplete(
  2095. ReceivedBuffer,
  2096. ReceivedBufferLength,
  2097. RuntimeConnection
  2098. );
  2099. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DRECV_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2100. return RpcStatus;
  2101. }
  2102. RPCRTAPI
  2103. RPC_STATUS
  2104. RPC_ENTRY
  2105. HTTP2WinHttpDirectSend (
  2106. IN void *Context,
  2107. OUT BYTE **SentBuffer,
  2108. OUT void **SendContext
  2109. )
  2110. /*++
  2111. Routine Description:
  2112. Direct notification from the thread pool to a sender
  2113. for a send. The stacks use that to post sends
  2114. to themselves.
  2115. Arguments:
  2116. Context - an instance of HTTP2WinHttpTransportChannel
  2117. SentBuffer - the buffer that we sent.
  2118. SendContext - the send context to return to the runtime
  2119. if the packet is not consumed.
  2120. Return Value:
  2121. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2122. --*/
  2123. {
  2124. RPC_STATUS RpcStatus;
  2125. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DSEND_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2126. RpcStatus = ((HTTP2WinHttpTransportChannel *)Context)->DirectSendComplete(
  2127. SentBuffer,
  2128. SendContext
  2129. );
  2130. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DSEND_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2131. return RpcStatus;
  2132. }
  2133. RPCRTAPI
  2134. RPC_STATUS
  2135. RPC_ENTRY
  2136. HTTP2PlugChannelDirectSend (
  2137. IN void *Context
  2138. )
  2139. /*++
  2140. Routine Description:
  2141. Direct notification from the thread pool to the plug channel
  2142. for a send. The plug channel uses that to post sends
  2143. to itself. Usable only on proxies (i.e. doesn't return to runtime)
  2144. Arguments:
  2145. Context - an instance of HTTP2PlugChannel
  2146. Return Value:
  2147. RPC_S_OK
  2148. --*/
  2149. {
  2150. return ((HTTP2PlugChannel *)Context)->DirectSendComplete();
  2151. }
  2152. RPCRTAPI
  2153. RPC_STATUS
  2154. RPC_ENTRY
  2155. HTTP2FlowControlChannelDirectSend (
  2156. IN void *Context,
  2157. OUT BOOL *IsServer,
  2158. OUT BOOL *SendToRuntime,
  2159. OUT void **SendContext,
  2160. OUT BUFFER *Buffer,
  2161. OUT UINT *BufferLength
  2162. )
  2163. /*++
  2164. Routine Description:
  2165. Direct notification from the thread pool to the flow control channel
  2166. for a send. The flow control channel uses that to post sends
  2167. to itself.
  2168. Arguments:
  2169. Context - an instance of HTTP2FlowControlSender
  2170. IsServer - on both success and failure MUST be set by this function.
  2171. SendToRuntime - on both success and failure MUST be set by this function.
  2172. SendContext - the send context as needs to be seen by the runtime
  2173. Buffer - on output the buffer that we tried to send
  2174. BufferLength - on output the length of the buffer we tried to send
  2175. Return Value:
  2176. RPC_S_OK
  2177. --*/
  2178. {
  2179. RPC_STATUS RpcStatus;
  2180. #if DBG
  2181. *IsServer = 0xBAADBAAD;
  2182. *SendToRuntime = 0xBAADBAAD;
  2183. #endif // DBG
  2184. RpcStatus = ((HTTP2FlowControlSender *)Context)->DirectSendComplete(IsServer,
  2185. SendToRuntime,
  2186. SendContext,
  2187. Buffer,
  2188. BufferLength);
  2189. // make sure DirectSendComplete didn't forget to set it
  2190. ASSERT(*IsServer != 0xBAADBAAD);
  2191. ASSERT(*SendToRuntime != 0xBAADBAAD);
  2192. return RpcStatus;
  2193. }
  2194. RPCRTAPI
  2195. RPC_STATUS
  2196. RPC_ENTRY
  2197. HTTP2ChannelDataOriginatorDirectSend (
  2198. IN void *Context,
  2199. OUT BOOL *IsServer,
  2200. OUT void **SendContext,
  2201. OUT BUFFER *Buffer,
  2202. OUT UINT *BufferLength
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. Direct notification from the thread pool to the channel data originator
  2207. for a send complete. The channel data originator uses that to post send
  2208. compeltes to itself. Usable only on endpoints (i.e. does return to runtime)
  2209. Arguments:
  2210. Context - an instance of HTTP2ChannelDataOriginator
  2211. IsServer - on both success and failure MUST be set by this function.
  2212. SendContext - the send context as needs to be seen by the runtime
  2213. Buffer - on output the buffer that we tried to send
  2214. BufferLength - on output the length of the buffer we tried to send
  2215. Return Value:
  2216. RPC_S_OK
  2217. --*/
  2218. {
  2219. RPC_STATUS RpcStatus;
  2220. #if DBG
  2221. *IsServer = 0xBAADBAAD;
  2222. #endif // DBG
  2223. RpcStatus = ((HTTP2ChannelDataOriginator *)Context)->DirectSendComplete(IsServer,
  2224. SendContext,
  2225. Buffer,
  2226. BufferLength);
  2227. // make sure DirectSendComplete didn't forget to set it
  2228. ASSERT(*IsServer != 0xBAADBAAD);
  2229. return RpcStatus;
  2230. }
  2231. RPCRTAPI
  2232. void
  2233. RPC_ENTRY
  2234. HTTP2TimerReschedule (
  2235. IN void *Context
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. A timer reschedule notification came in.
  2240. Arguments:
  2241. Context - actually a ping channel pointer for the channel
  2242. that asked for rescheduling
  2243. Return Value:
  2244. --*/
  2245. {
  2246. HTTP2PingOriginator *PingChannel;
  2247. PingChannel = (HTTP2PingOriginator *)Context;
  2248. PingChannel->RescheduleTimer();
  2249. }
  2250. RPCRTAPI
  2251. void
  2252. RPC_ENTRY
  2253. HTTP2AbortConnection (
  2254. IN void *Context
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. A request to abort the connection was posted on a worker thread.
  2259. Arguments:
  2260. Context - actually a top channel pointer for the connection to abort.
  2261. Return Value:
  2262. --*/
  2263. {
  2264. HTTP2Channel *TopChannel;
  2265. TopChannel = (HTTP2Channel *)Context;
  2266. TopChannel->AbortConnection(RPC_P_CONNECTION_SHUTDOWN);
  2267. TopChannel->RemoveReference();
  2268. }
  2269. RPCRTAPI
  2270. void
  2271. RPC_ENTRY
  2272. HTTP2RecycleChannel (
  2273. IN void *Context
  2274. )
  2275. /*++
  2276. Routine Description:
  2277. A request to recycle the channel was posted on a worker thread.
  2278. Arguments:
  2279. Context - actually a top channel pointer for the channel to
  2280. recycle.
  2281. Return Value:
  2282. --*/
  2283. {
  2284. HTTP2Channel *TopChannel;
  2285. TopChannel = (HTTP2Channel *)Context;
  2286. // don't care about return code. See rule 29.
  2287. (void) TopChannel->HandleSendResultFromNeutralContext(RPC_P_CHANNEL_NEEDS_RECYCLING);
  2288. TopChannel->RemoveReference();
  2289. }
  2290. RPC_STATUS
  2291. HTTP2ProcessComplexTReceive (
  2292. IN OUT void **Connection,
  2293. IN RPC_STATUS EventStatus,
  2294. IN ULONG Bytes,
  2295. OUT BUFFER *Buffer,
  2296. OUT UINT *BufferLength
  2297. )
  2298. /*++
  2299. Routine Description:
  2300. A receive notification came from the completion port.
  2301. Arguments:
  2302. Connection - a pointer to a pointer to a connection.
  2303. On input it will be the raw connection. On output
  2304. it needs to be the virtual connection so that
  2305. runtime can find its object off there. This out
  2306. parameter must be set on both success and failure.
  2307. EventStatus - status of the operation
  2308. Bytes - bytes received
  2309. Buffer - on output (success only), the received buffer
  2310. BufferLength - on output (success only), the length of the
  2311. received buffer.
  2312. Return Value:
  2313. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2314. RPC_P_PARTIAL_RECEIVE allowed for partial receives.
  2315. RPC_P_PACKET_CONSUMED must be returned for all transport
  2316. traffic (success or failure). Anything else will AV the
  2317. runtime.
  2318. --*/
  2319. {
  2320. WS_HTTP2_CONNECTION *RawConnection = (WS_HTTP2_CONNECTION *)*Connection;
  2321. LOG_FN_OPERATION_ENTRY(HTTP2LOG_COMPLEX_T_RECV, HTTP2LOG_OT_CALLBACK, EventStatus);
  2322. // in rare cases a receive can be consumed within the transport
  2323. // outside the ComplexT mechanism (server connection establishment is
  2324. // the only example). Ignore such packets.
  2325. if (EventStatus == RPC_P_PACKET_CONSUMED)
  2326. return EventStatus;
  2327. // stick the runtime idea of the transport connection
  2328. *Connection = RawConnection->RuntimeConnectionPtr;
  2329. if (Bytes && (EventStatus == RPC_S_OK))
  2330. {
  2331. EventStatus = RawConnection->ProcessReceiveComplete(Bytes,
  2332. Buffer,
  2333. BufferLength);
  2334. if (EventStatus == RPC_P_PARTIAL_RECEIVE)
  2335. {
  2336. // Message is not complete, submit the next read and continue.
  2337. EventStatus = CO_SubmitRead(RawConnection);
  2338. if (EventStatus != RPC_S_OK)
  2339. {
  2340. EventStatus = RawConnection->ProcessReceiveFailed(RPC_P_CONNECTION_SHUTDOWN);
  2341. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2342. {
  2343. ASSERT(EventStatus == RPC_P_RECEIVE_FAILED);
  2344. }
  2345. }
  2346. else
  2347. EventStatus = RPC_P_PARTIAL_RECEIVE;
  2348. }
  2349. else
  2350. {
  2351. ASSERT( (EventStatus == RPC_P_RECEIVE_FAILED)
  2352. || (EventStatus == RPC_S_OK)
  2353. || (EventStatus == RPC_P_PACKET_CONSUMED));
  2354. }
  2355. }
  2356. else
  2357. {
  2358. // in other rare case (again server connection establishment), the connection
  2359. // can be the virtual connection, not the transport connection. In such cases,
  2360. // let the error fall through back to the runtime. Since this happens only during
  2361. // connection establishment, and the receive did not go through the channels,
  2362. // we should not complete it through the channels.
  2363. if ((RawConnection->id == HTTPv2)
  2364. && (RawConnection->type == (COMPLEX_T | CONNECTION | SERVER)))
  2365. {
  2366. // this is a server virtual connecton. Read the connection from there
  2367. *Connection = RawConnection;
  2368. }
  2369. else
  2370. {
  2371. if (EventStatus != RPC_S_OK)
  2372. EventStatus = RawConnection->ProcessReceiveFailed(EventStatus);
  2373. else
  2374. EventStatus = RawConnection->ProcessReceiveFailed(RPC_P_RECEIVE_FAILED);
  2375. if (EventStatus == RPC_P_CONNECTION_SHUTDOWN)
  2376. EventStatus = RPC_P_RECEIVE_FAILED;
  2377. }
  2378. ASSERT( (EventStatus == RPC_P_RECEIVE_FAILED)
  2379. || (EventStatus == RPC_S_OK)
  2380. || (EventStatus == RPC_P_PACKET_CONSUMED));
  2381. }
  2382. LOG_FN_OPERATION_EXIT(HTTP2LOG_COMPLEX_T_RECV, HTTP2LOG_OT_CALLBACK, EventStatus);
  2383. return EventStatus;
  2384. }
  2385. RPC_STATUS
  2386. HTTP2ProcessComplexTSend (
  2387. IN void *SendContext,
  2388. IN RPC_STATUS EventStatus,
  2389. OUT BUFFER *Buffer
  2390. )
  2391. /*++
  2392. Routine Description:
  2393. A send notification came from the completion port.
  2394. Arguments:
  2395. SendContext - the send context
  2396. EventStatus - status of the operation
  2397. Buffer - if the packet is not consumed, must be the sent
  2398. buffer.
  2399. Return Value:
  2400. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2401. RPC_P_PACKET_CONSUMED must be returned for all transport
  2402. traffic (success or failure). Anything else will AV the
  2403. runtime.
  2404. --*/
  2405. {
  2406. HTTP2SendContext *HttpSendContext = (HTTP2SendContext *)SendContext;
  2407. WS_HTTP2_CONNECTION *RawConnection;
  2408. RPC_STATUS RpcStatus;
  2409. LOG_FN_OPERATION_ENTRY(HTTP2LOG_COMPLEX_T_SEND, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)HttpSendContext);
  2410. *Buffer = HttpSendContext->pWriteBuffer;
  2411. RawConnection = (WS_HTTP2_CONNECTION *)HttpSendContext->Write.pAsyncObject;
  2412. RpcStatus = RawConnection->ProcessSendComplete(EventStatus, HttpSendContext);
  2413. LOG_FN_OPERATION_EXIT(HTTP2LOG_COMPLEX_T_SEND, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2414. return RpcStatus;
  2415. }
  2416. RPC_STATUS ProxyAsyncCompleteHelper (
  2417. IN HTTP2Channel *TopChannel,
  2418. IN RPC_STATUS CurrentStatus
  2419. )
  2420. /*++
  2421. Routine Description:
  2422. A helper function that completes an async io.
  2423. Arguments:
  2424. TopChannel - the top channel for the stack
  2425. CurrentStatus - the status with which the complete
  2426. notification completed.
  2427. Return Value:
  2428. RPC_S_OK.
  2429. --*/
  2430. {
  2431. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  2432. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  2433. if ((CurrentStatus != RPC_S_OK)
  2434. &&
  2435. (CurrentStatus != RPC_P_PACKET_CONSUMED))
  2436. {
  2437. // if this failed, abort the whole connection
  2438. TopChannel->AbortAndDestroyConnection(CurrentStatus);
  2439. }
  2440. TopChannel->RemoveReference();
  2441. return RPC_S_OK;
  2442. }
  2443. RPCRTAPI
  2444. RPC_STATUS
  2445. RPC_ENTRY
  2446. HTTP2TestHook (
  2447. IN SystemFunction001Commands FunctionCode,
  2448. IN void *InData,
  2449. OUT void *OutData
  2450. )
  2451. /*++
  2452. Routine Description:
  2453. Test hook for the http functions
  2454. Arguments:
  2455. FunctionCode - which test function to perform
  2456. InData - input data from the test function
  2457. OutData - output data from the test function
  2458. Return Value:
  2459. RPC_S_OK or RPC_S_* error
  2460. --*/
  2461. {
  2462. RPC_CHAR *NewTarget;
  2463. switch (FunctionCode)
  2464. {
  2465. case sf001cHttpSetInChannelTarget:
  2466. NewTarget = (RPC_CHAR *)InData;
  2467. if (InChannelTargetTestOverride)
  2468. {
  2469. delete [] InChannelTargetTestOverride;
  2470. InChannelTargetTestOverride = NULL;
  2471. }
  2472. if (NewTarget)
  2473. {
  2474. InChannelTargetTestOverride = DuplicateString(NewTarget);
  2475. if (InChannelTargetTestOverride == NULL)
  2476. return RPC_S_OUT_OF_MEMORY;
  2477. }
  2478. break;
  2479. case sf001cHttpSetOutChannelTarget:
  2480. NewTarget = (RPC_CHAR *)InData;
  2481. if (OutChannelTargetTestOverride)
  2482. {
  2483. delete [] OutChannelTargetTestOverride;
  2484. OutChannelTargetTestOverride = NULL;
  2485. }
  2486. if (NewTarget)
  2487. {
  2488. OutChannelTargetTestOverride = DuplicateString(NewTarget);
  2489. if (OutChannelTargetTestOverride == NULL)
  2490. return RPC_S_OUT_OF_MEMORY;
  2491. }
  2492. break;
  2493. default:
  2494. // we should never be called with a value we can't handle
  2495. ASSERT(0);
  2496. return RPC_S_INTERNAL_ERROR;
  2497. }
  2498. return RPC_S_OK;
  2499. }
  2500. /*********************************************************************
  2501. HTTP2TransportChannel
  2502. *********************************************************************/
  2503. RPC_STATUS HTTP2TransportChannel::Send (
  2504. IN OUT HTTP2SendContext *SendContext
  2505. )
  2506. /*++
  2507. Routine Description:
  2508. Send request
  2509. Arguments:
  2510. SendContext - the send context
  2511. Return Value:
  2512. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2513. --*/
  2514. {
  2515. VerifyValidSendContext(SendContext);
  2516. return LowerLayer->Send(SendContext);
  2517. }
  2518. RPC_STATUS HTTP2TransportChannel::Receive (
  2519. IN HTTP2TrafficType TrafficType
  2520. )
  2521. /*++
  2522. Routine Description:
  2523. Receive request
  2524. Arguments:
  2525. TrafficType - the type of traffic we want to receive
  2526. Return Value:
  2527. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2528. --*/
  2529. {
  2530. return LowerLayer->Receive(TrafficType);
  2531. }
  2532. RPC_STATUS HTTP2TransportChannel::SendComplete (
  2533. IN RPC_STATUS EventStatus,
  2534. IN OUT HTTP2SendContext *SendContext
  2535. )
  2536. /*++
  2537. Routine Description:
  2538. Send complete notification
  2539. Arguments:
  2540. EventStatus - the status of the send
  2541. SendContext - send context
  2542. Return Value:
  2543. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2544. --*/
  2545. {
  2546. return UpperLayer->SendComplete(EventStatus,
  2547. SendContext
  2548. );
  2549. }
  2550. RPC_STATUS HTTP2TransportChannel::ReceiveComplete (
  2551. IN RPC_STATUS EventStatus,
  2552. IN HTTP2TrafficType TrafficType,
  2553. IN BYTE *Buffer,
  2554. IN UINT BufferLength
  2555. )
  2556. /*++
  2557. Routine Description:
  2558. Receive complete notification.
  2559. Arguments:
  2560. EventStatus - status of the operation
  2561. TrafficType - the type of traffic we have received
  2562. Buffer - the received buffer (success only)
  2563. BufferLength - the length of the received buffer (success only)
  2564. Return Value:
  2565. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2566. --*/
  2567. {
  2568. return UpperLayer->ReceiveComplete(EventStatus,
  2569. TrafficType,
  2570. Buffer,
  2571. BufferLength
  2572. );
  2573. }
  2574. void HTTP2TransportChannel::Abort (
  2575. IN RPC_STATUS RpcStatus
  2576. )
  2577. /*++
  2578. Routine Description:
  2579. Abort the channel
  2580. Arguments:
  2581. RpcStatus - the error code with which we abort
  2582. Return Value:
  2583. --*/
  2584. {
  2585. LowerLayer->Abort(RpcStatus);
  2586. }
  2587. void HTTP2TransportChannel::SendCancelled (
  2588. IN HTTP2SendContext *SendContext
  2589. )
  2590. /*++
  2591. Routine Description:
  2592. A lower channel cancelled a send already passed through this channel.
  2593. Most channels don't care as they don't account for or hang on to sends.
  2594. Called only in submission context.
  2595. Arguments:
  2596. SendContext - the send context of the send that was cancelled
  2597. Return Value:
  2598. --*/
  2599. {
  2600. UpperLayer->SendCancelled(SendContext);
  2601. }
  2602. void HTTP2TransportChannel::Reset (
  2603. void
  2604. )
  2605. /*++
  2606. Routine Description:
  2607. Reset the channel for next open/send/receive. This is
  2608. used in submission context only and implies there are no
  2609. pending operations on the channel. It is used on the client
  2610. during opening the connection to do quick negotiation on the
  2611. same connection instead of opening a new connection every time.
  2612. Arguments:
  2613. Return Value:
  2614. --*/
  2615. {
  2616. if (LowerLayer)
  2617. LowerLayer->Reset();
  2618. }
  2619. RPC_STATUS HTTP2TransportChannel::AsyncCompleteHelper (
  2620. IN RPC_STATUS CurrentStatus
  2621. )
  2622. /*++
  2623. Routine Description:
  2624. Helper routine that helps complete an async operation
  2625. Arguments:
  2626. CurrentStatus - the current status of the operation
  2627. Return Value:
  2628. The status to return to the runtime.
  2629. --*/
  2630. {
  2631. return TopChannel->AsyncCompleteHelper(CurrentStatus);
  2632. }
  2633. RPC_STATUS HTTP2TransportChannel::HandleSendResultFromNeutralContext (
  2634. IN RPC_STATUS CurrentStatus
  2635. )
  2636. /*++
  2637. Routine Description:
  2638. Handles the result code from send from a neutral context.
  2639. This includes checking for channel recycling and intiating
  2640. one if necessary. This routine simply delegates to the top channel
  2641. Arguments:
  2642. CurrentStatus - the status from the send operation
  2643. Return Value:
  2644. RPC_S_OK or RPC_S_*. Callers may ignore it since all cleanup was
  2645. done.
  2646. Notes:
  2647. This must be called in upcall or neutral context only
  2648. --*/
  2649. {
  2650. return TopChannel->HandleSendResultFromNeutralContext(CurrentStatus);
  2651. }
  2652. /*********************************************************************
  2653. WS_HTTP2_CONNECTION
  2654. *********************************************************************/
  2655. RPC_STATUS WS_HTTP2_CONNECTION::Send(HANDLE hFile, LPCVOID lpBuffer,
  2656. DWORD nNumberOfBytesToWrite,
  2657. LPDWORD lpNumberOfBytesWritten,
  2658. LPOVERLAPPED lpOverlapped)
  2659. /*++
  2660. Routine Description:
  2661. Does an asynchronous send on the connection.
  2662. Arguments:
  2663. hFile - file to send on
  2664. lpBuffer - buffer to send
  2665. nNumberOfBytesToWrite - number of bytes to send
  2666. lpNumberOfBytesWritten - number of bytes written. Will never get filled
  2667. in this code path because it is async.
  2668. lpOverlapped - overlapped to use for the operation
  2669. Return Value:
  2670. WSA Error Code
  2671. --*/
  2672. {
  2673. // See Rule 32.
  2674. return UTIL_WriteFile2(hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped);
  2675. }
  2676. RPC_STATUS WS_HTTP2_CONNECTION::Receive(HANDLE hFile,
  2677. LPVOID lpBuffer,
  2678. DWORD nNumberOfBytesToRead,
  2679. LPDWORD lpNumberOfBytesRead,
  2680. LPOVERLAPPED lpOverlapped
  2681. )
  2682. /*++
  2683. Routine Description:
  2684. Does an asynchronous receive on the connection.
  2685. Arguments:
  2686. hFile - file to receive on
  2687. lpBuffer - buffer to receive into
  2688. nNumberOfBytesToRead - number of bytes to receive
  2689. lpNumberOfBytesRead - number of bytes read. Will never get filled
  2690. in this code path because it is async.
  2691. lpOverlapped - overlapped to use for the operation
  2692. Return Value:
  2693. WSA Error Code
  2694. --*/
  2695. {
  2696. return SANReceive(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
  2697. }
  2698. RPC_STATUS WS_HTTP2_CONNECTION::ProcessReceiveFailed (
  2699. IN RPC_STATUS EventStatus
  2700. )
  2701. /*++
  2702. Routine Description:
  2703. Notifies a raw connection of receive failure.
  2704. Arguments:
  2705. EventStatus - error with which the receive failed
  2706. Return Value:
  2707. RPC_S_OK to return packet to runtime
  2708. or RPC_P_PACKET_CONSUMED to hide it.
  2709. --*/
  2710. {
  2711. // if we failed before we parsed the header, chances are the problem
  2712. // was with the header format. Treat it as protocol error.
  2713. if ((HeaderRead == FALSE) && (EventStatus == RPC_P_CONNECTION_SHUTDOWN))
  2714. EventStatus = RPC_S_PROTOCOL_ERROR;
  2715. return Channel->ReceiveComplete(EventStatus, http2ttRaw, pReadBuffer, 0);
  2716. }
  2717. RPC_STATUS WS_HTTP2_CONNECTION::ProcessSendComplete (
  2718. IN RPC_STATUS EventStatus,
  2719. IN CO_SEND_CONTEXT *SendContext
  2720. )
  2721. /*++
  2722. Routine Description:
  2723. Notifies a raw connection of send completion (fail or succeed).
  2724. Arguments:
  2725. EventStatus - error with which the send failed
  2726. Return Value:
  2727. RPC_S_OK to return packet to runtime
  2728. or RPC_P_PACKET_CONSUMED to hide it.
  2729. --*/
  2730. {
  2731. HTTP2SendContext *HttpSendContext = (HTTP2SendContext *)SendContext;
  2732. VerifyValidSendContext(HttpSendContext);
  2733. return Channel->SendComplete(EventStatus, HttpSendContext);
  2734. }
  2735. RPC_STATUS WS_HTTP2_CONNECTION::ProcessRead(
  2736. IN DWORD bytes,
  2737. OUT BUFFER *pBuffer,
  2738. OUT PUINT pBufferLength
  2739. )
  2740. /*++
  2741. Routine Description:
  2742. Processes a connection oriented receive
  2743. complete. But in HTTP2 we no-op this and do all read
  2744. processing through the COMPLEX_T mechanism.
  2745. Arguments:
  2746. bytes - the number of read (not including those in iLastRead).
  2747. pBuffer - when returning RPC_S_OK will contain the message.
  2748. pBufferLength - when return RPC_S_OK will contain the message length.
  2749. Return Value:
  2750. RPC_S_OK
  2751. --*/
  2752. {
  2753. return RPC_S_OK;
  2754. }
  2755. RPC_STATUS WS_HTTP2_CONNECTION::ProcessReceiveComplete(
  2756. IN DWORD bytes,
  2757. OUT BUFFER *pBuffer,
  2758. OUT PUINT pBufferLength
  2759. )
  2760. /*++
  2761. Routine Description:
  2762. Processes a connection oriented receive
  2763. complete. It takes care of fragmentation.
  2764. Arguments:
  2765. bytes - the number of read (not including those in iLastRead).
  2766. pBuffer - when returning RPC_S_OK will contain the message.
  2767. pBufferLength - when return RPC_S_OK will contain the message length.
  2768. Return Value:
  2769. RPC_S_OK to return packet to runtime
  2770. or RPC_P_PACKET_CONSUMED to hide it.
  2771. --*/
  2772. {
  2773. RPC_STATUS RpcStatus;
  2774. if (HeaderRead)
  2775. {
  2776. RpcStatus = BASE_CONNECTION::ProcessRead(bytes, pBuffer, pBufferLength);
  2777. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2778. return RpcStatus;
  2779. }
  2780. else if (bytes != 0)
  2781. {
  2782. ASSERT(ReadHeaderFn);
  2783. RpcStatus = ReadHeaderFn(this,
  2784. bytes,
  2785. (ULONG *)pBufferLength
  2786. );
  2787. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2788. return RpcStatus;
  2789. if (RpcStatus == RPC_S_OK)
  2790. {
  2791. RpcStatus = BASE_CONNECTION::ProcessRead(*pBufferLength, pBuffer, pBufferLength);
  2792. }
  2793. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2794. return RpcStatus;
  2795. }
  2796. else
  2797. {
  2798. RpcStatus = RPC_P_CONNECTION_CLOSED;
  2799. }
  2800. if (RpcStatus == RPC_S_OK)
  2801. {
  2802. RpcStatus = Channel->ReceiveComplete(RpcStatus,
  2803. http2ttRaw,
  2804. (BYTE *)*pBuffer,
  2805. *pBufferLength);
  2806. }
  2807. else
  2808. {
  2809. RpcStatus = Channel->ReceiveComplete(RpcStatus,
  2810. http2ttRaw,
  2811. NULL,
  2812. 0);
  2813. }
  2814. return RpcStatus;
  2815. }
  2816. RPC_STATUS WS_HTTP2_CONNECTION::Abort (
  2817. void
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. No-op. This is called from common
  2822. transport code. We don't abort HTTP2
  2823. connections from common transport code. Ignore
  2824. this call.
  2825. Arguments:
  2826. Return Value:
  2827. RPC_S_OK
  2828. --*/
  2829. {
  2830. return RPC_S_OK;
  2831. }
  2832. void WS_HTTP2_CONNECTION::Free (
  2833. void
  2834. )
  2835. /*++
  2836. Routine Description:
  2837. Acts like destructor. All memory needs to
  2838. be freed.
  2839. Arguments:
  2840. Return Value:
  2841. RPC_S_OK
  2842. --*/
  2843. {
  2844. if (pReadBuffer)
  2845. {
  2846. RpcFreeBuffer(pReadBuffer);
  2847. pReadBuffer = NULL;
  2848. }
  2849. // make sure we don't free the connection without closing the socket.
  2850. // When we close the socket, we set it to NULL.
  2851. ASSERT(Conn.Socket == NULL);
  2852. }
  2853. void WS_HTTP2_CONNECTION::RealAbort (
  2854. void
  2855. )
  2856. /*++
  2857. Routine Description:
  2858. Aborts an HTTP2 connection.
  2859. Arguments:
  2860. Return Value:
  2861. --*/
  2862. {
  2863. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_RAW_CONNECTION, 0);
  2864. (void)WS_CONNECTION::Abort();
  2865. if (!RpcpIsListEmpty(&ObjectList))
  2866. {
  2867. TransportProtocol::RemoveObjectFromProtocolList(this);
  2868. }
  2869. }
  2870. void WS_HTTP2_CONNECTION::Initialize (
  2871. void
  2872. )
  2873. /*++
  2874. Routine Description:
  2875. Initializes a raw connection
  2876. Arguments:
  2877. Return Value:
  2878. --*/
  2879. {
  2880. BASE_CONNECTION::Initialize();
  2881. #if DBG
  2882. // client and server virtual connections must initialize this. In debug
  2883. // builds toast anybody who forgets. Proxies don't care
  2884. type = 0xC0C0C0C0;
  2885. #endif
  2886. pAddress = NULL;
  2887. RpcpInitializeListHead(&ObjectList);
  2888. // use explicit placement to initialize the vtable. We need this to
  2889. // be able to use the virtual functions
  2890. (void) new (this) WS_HTTP2_CONNECTION;
  2891. }
  2892. /*********************************************************************
  2893. WS_HTTP2_INITIAL_CONNECTION
  2894. *********************************************************************/
  2895. C_ASSERT(sizeof(rpcconn_common) == sizeof(CONN_RPC_HEADER));
  2896. RPC_STATUS WS_HTTP2_INITIAL_CONNECTION::ProcessRead(
  2897. IN DWORD BytesRead,
  2898. OUT BUFFER *pBuffer,
  2899. OUT PUINT pBufferLength
  2900. )
  2901. /*++
  2902. Routine Description:
  2903. Processes a connection oriented receive
  2904. complete. It determines whether HTTP2 or HTTP will be
  2905. used and initializes the stack accordingly.
  2906. Arguments:
  2907. BytesRead - the number of read (not including those in iLastRead).
  2908. pBuffer - when returning RPC_S_OK will contain the message.
  2909. pBufferLength - when return RPC_S_OK will contain the message length.
  2910. Return Value:
  2911. RPC_S_OK for successful processing
  2912. RPC_PARTIAL_RECEIVE - not enough was received to tell
  2913. RPC_P_PACKET_CONSUMED - the packet was consumed.
  2914. RPC_P_RECEIVE_FAILED - error occurred.
  2915. --*/
  2916. {
  2917. RPC_STATUS RpcStatus;
  2918. BYTE *Packet;
  2919. ULONG PacketLength;
  2920. BOOL IsD1_A2Packet;
  2921. WS_HTTP2_INITIAL_CONNECTION *ThisConnection;
  2922. HTTP2ServerVirtualConnection *ServerVirtualConnection;
  2923. BOOL VirtualConnectionCreated;
  2924. RpcStatus = BASE_CONNECTION::ProcessRead(BytesRead,
  2925. pBuffer,
  2926. pBufferLength
  2927. );
  2928. if (RpcStatus == RPC_S_OK)
  2929. {
  2930. // ProcessRead guarantees that on return value of RPC_S_OK
  2931. // we have at least rpcconn_common bytes read successfully
  2932. Packet = (BYTE *)*pBuffer;
  2933. PacketLength = *pBufferLength;
  2934. if (IsRTSPacket(Packet))
  2935. {
  2936. // HTTP2 traffic.
  2937. ThisConnection = this;
  2938. // unlink this connection from the PnP list before it is migrated
  2939. TransportProtocol::RemoveObjectFromProtocolList((BASE_ASYNC_OBJECT *) ThisConnection);
  2940. RpcStatus = HTTP2ServerVirtualConnection::InitializeServerConnection (
  2941. Packet,
  2942. PacketLength,
  2943. ThisConnection,
  2944. &ServerVirtualConnection,
  2945. &VirtualConnectionCreated
  2946. );
  2947. if (RpcStatus == RPC_S_OK)
  2948. {
  2949. // N.B. Do not use the this pointer as WS_HTTP2_INITIAL_CONNECTION
  2950. // pointer after here. It has been migrated to a new location
  2951. // and this actually points to HTTP2ServerVirtualConnection
  2952. // Make sure HTTP2ServerVirtualConnection didn't forget to
  2953. // initialize its type member
  2954. ASSERT(this->id == HTTPv2);
  2955. ASSERT(this->type & COMPLEX_T);
  2956. *pBuffer = NULL;
  2957. *pBufferLength = 0;
  2958. RpcFreeBuffer(Packet);
  2959. RpcStatus = RPC_P_PACKET_CONSUMED;
  2960. }
  2961. else
  2962. {
  2963. if (VirtualConnectionCreated == FALSE)
  2964. {
  2965. // failed to create a virtual connection. Link the connection
  2966. // back to its protocol list to ensure orderly destruction
  2967. TransportProtocol::AddObjectToProtocolList((BASE_ASYNC_OBJECT *) this);
  2968. }
  2969. else
  2970. {
  2971. // nothing to do. The virtual connection was created but it failed to
  2972. // initialize. Return failure, and the runtime will turn around and
  2973. // destroy the connection
  2974. }
  2975. RpcStatus = RPC_P_RECEIVE_FAILED;
  2976. }
  2977. }
  2978. else
  2979. {
  2980. // morph the connection into WS_CONNECTION to serve
  2981. // HTTP requests. The only thing we need to change is the
  2982. // vtable. We have a little bit of extra goo at the end, but
  2983. // that's ok.
  2984. (void) new (this) WS_CONNECTION;
  2985. }
  2986. }
  2987. return RpcStatus;
  2988. }
  2989. RPC_STATUS WS_HTTP2_INITIAL_CONNECTION::Abort(
  2990. void
  2991. )
  2992. /*++
  2993. Routine Description:
  2994. Aborts an WS_HTTP2_INITIAL_CONNECTION connection.
  2995. Very rare to be called.
  2996. Arguments:
  2997. Return Value:
  2998. RPC_S_OK
  2999. --*/
  3000. {
  3001. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_INITIAL_RAW_CONNECTION, 0);
  3002. WS_HTTP2_CONNECTION::RealAbort();
  3003. return RPC_S_OK;
  3004. }
  3005. /*********************************************************************
  3006. HTTP2BottomChannel
  3007. *********************************************************************/
  3008. RPC_STATUS HTTP2BottomChannel::SendComplete (
  3009. IN RPC_STATUS EventStatus,
  3010. IN OUT HTTP2SendContext *SendContext
  3011. )
  3012. /*++
  3013. Routine Description:
  3014. Send complete notification
  3015. Arguments:
  3016. EventStatus - status of the operation
  3017. SendContext - the send context
  3018. Return Value:
  3019. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3020. --*/
  3021. {
  3022. RPC_STATUS RpcStatus;
  3023. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, EventStatus);
  3024. RpcStatus = HTTP2TransportChannel::SendComplete(EventStatus,
  3025. SendContext
  3026. );
  3027. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, RpcStatus);
  3028. return AsyncCompleteHelper(RpcStatus);
  3029. }
  3030. RPC_STATUS HTTP2BottomChannel::ReceiveComplete (
  3031. IN RPC_STATUS EventStatus,
  3032. IN HTTP2TrafficType TrafficType,
  3033. IN BYTE *Buffer,
  3034. IN UINT BufferLength
  3035. )
  3036. /*++
  3037. Routine Description:
  3038. Receive complete notification
  3039. Arguments:
  3040. EventStatus - status of the operation
  3041. TrafficType - the type of traffic we have received
  3042. Buffer - the received buffer (success only)
  3043. BufferLength - the length of the received buffer (success only)
  3044. Return Value:
  3045. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3046. --*/
  3047. {
  3048. RPC_STATUS RpcStatus;
  3049. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, EventStatus);
  3050. RpcStatus = HTTP2TransportChannel::ReceiveComplete(EventStatus,
  3051. TrafficType,
  3052. Buffer,
  3053. BufferLength
  3054. );
  3055. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, RpcStatus);
  3056. return AsyncCompleteHelper(RpcStatus);
  3057. }
  3058. /*********************************************************************
  3059. HTTP2SocketTransportChannel
  3060. *********************************************************************/
  3061. RPC_STATUS HTTP2SocketTransportChannel::Send (
  3062. IN OUT HTTP2SendContext *SendContext
  3063. )
  3064. /*++
  3065. Routine Description:
  3066. Send request. Forward the send to the raw connection
  3067. Arguments:
  3068. SendContext - the send context
  3069. Return Value:
  3070. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3071. --*/
  3072. {
  3073. RPC_STATUS RpcStatus;
  3074. DWORD Ignored;
  3075. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, (ULONG_PTR)SendContext);
  3076. // route this through the completion port
  3077. SendContext->Write.ol.hEvent = NULL;
  3078. SendContext->Write.pAsyncObject = RawConnection;
  3079. // N.B. The Winsock provider will touch the overlapped on the return path. We need
  3080. // to make sure that either the overlapped is around (in which case we can use WSASend),
  3081. // or otherwise use UTIL_WriteFile2 which does not touch the overlapped on return.
  3082. // We know the overlapped may not be around when this is a proxy data send, any type
  3083. // of RTS send, or abandoned send. All non-proxy, not-abandoned data sends will have
  3084. // the overlapped around.
  3085. if ((SendContext->TrafficType == http2ttData)
  3086. && (((SendContext->Flags & (SendContextFlagAbandonedSend | SendContextFlagProxySend)) == 0)))
  3087. {
  3088. RpcStatus = RawConnection->WS_HTTP2_CONNECTION::SANSend(
  3089. RawConnection->Conn.Handle,
  3090. SendContext->pWriteBuffer,
  3091. SendContext->maxWriteBuffer,
  3092. &Ignored,
  3093. &SendContext->Write.ol
  3094. );
  3095. }
  3096. else
  3097. {
  3098. RpcStatus = RawConnection->WS_HTTP2_CONNECTION::Send(
  3099. RawConnection->Conn.Handle,
  3100. SendContext->pWriteBuffer,
  3101. SendContext->maxWriteBuffer,
  3102. &Ignored,
  3103. &SendContext->Write.ol
  3104. );
  3105. }
  3106. if ( (RpcStatus != RPC_S_OK)
  3107. && (RpcStatus != ERROR_IO_PENDING) )
  3108. {
  3109. VALIDATE(RpcStatus)
  3110. {
  3111. ERROR_NETNAME_DELETED,
  3112. ERROR_GRACEFUL_DISCONNECT,
  3113. ERROR_NO_DATA,
  3114. ERROR_NO_SYSTEM_RESOURCES,
  3115. ERROR_WORKING_SET_QUOTA,
  3116. ERROR_BAD_COMMAND,
  3117. ERROR_OPERATION_ABORTED,
  3118. ERROR_WORKING_SET_QUOTA,
  3119. WSAECONNABORTED,
  3120. WSAECONNRESET
  3121. } END_VALIDATE;
  3122. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, RPC_P_SEND_FAILED);
  3123. return(RPC_P_SEND_FAILED);
  3124. }
  3125. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, RPC_S_OK);
  3126. return RPC_S_OK;
  3127. }
  3128. RPC_STATUS HTTP2SocketTransportChannel::Receive (
  3129. IN HTTP2TrafficType TrafficType
  3130. )
  3131. {
  3132. RPC_STATUS RpcStatus;
  3133. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_SOCKET_CHANNEL, TrafficType);
  3134. ASSERT(TrafficType == http2ttRaw);
  3135. RpcStatus = CO_Recv(RawConnection);
  3136. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_SOCKET_CHANNEL, RpcStatus);
  3137. return RpcStatus;
  3138. }
  3139. void HTTP2SocketTransportChannel::Abort (
  3140. IN RPC_STATUS RpcStatus
  3141. )
  3142. /*++
  3143. Routine Description:
  3144. Abort the channel
  3145. Arguments:
  3146. RpcStatus - the error code with which we abort
  3147. Return Value:
  3148. --*/
  3149. {
  3150. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_SOCKET_CHANNEL, RpcStatus);
  3151. RawConnection->RealAbort();
  3152. }
  3153. void HTTP2SocketTransportChannel::FreeObject (
  3154. void
  3155. )
  3156. /*++
  3157. Routine Description:
  3158. Frees the object. Acts like a destructor for the
  3159. channel.
  3160. Arguments:
  3161. Return Value:
  3162. --*/
  3163. {
  3164. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_SOCKET_CHANNEL, 0);
  3165. RawConnection->Free();
  3166. HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  3167. }
  3168. void HTTP2SocketTransportChannel::Reset (
  3169. void
  3170. )
  3171. /*++
  3172. Routine Description:
  3173. Reset the channel for next open/send/receive. This is
  3174. used in submission context only and implies there are no
  3175. pending operations on the channel. It is used on the client
  3176. during opening the connection to do quick negotiation on the
  3177. same connection instead of opening a new connection every time.
  3178. Arguments:
  3179. Return Value:
  3180. --*/
  3181. {
  3182. RawConnection->HeaderRead = FALSE;
  3183. }
  3184. /*********************************************************************
  3185. HTTP2FragmentReceiver
  3186. *********************************************************************/
  3187. RPC_STATUS HTTP2FragmentReceiver::Receive (
  3188. IN HTTP2TrafficType TrafficType
  3189. )
  3190. /*++
  3191. Routine Description:
  3192. Receive request
  3193. Arguments:
  3194. TrafficType - the type of traffic we want to receive
  3195. Return Value:
  3196. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3197. --*/
  3198. {
  3199. if (iLastRead && iLastRead == MaxReadBuffer)
  3200. {
  3201. ASSERT(pReadBuffer);
  3202. // This means we received a coalesced read of a complete
  3203. // message. (Or that we received a coalesced read < header size)
  3204. // We should complete that as it's own IO in neutral context.
  3205. // This is very rare.
  3206. (void) COMMON_PostRuntimeEvent(GetPostRuntimeEvent(),
  3207. this
  3208. );
  3209. return(RPC_S_OK);
  3210. }
  3211. ASSERT(iLastRead == 0 || (iLastRead < MaxReadBuffer));
  3212. return(PostReceive());
  3213. };
  3214. RPC_STATUS HTTP2FragmentReceiver::ReceiveComplete (
  3215. IN RPC_STATUS EventStatus,
  3216. IN HTTP2TrafficType TrafficType,
  3217. IN OUT BYTE **Buffer,
  3218. IN OUT UINT *BufferLength
  3219. )
  3220. /*++
  3221. Routine Description:
  3222. Processes a receive complete notification.
  3223. Arguments:
  3224. EventStatus - the status code of the operation.
  3225. TrafficType - the type of traffic we have received
  3226. Buffer - the buffer. Must be NULL at this level on input. On
  3227. output contains the buffer for the current receive. If NULL
  3228. on output, we did not have a full packet. Undefined on failure.
  3229. BufferLength - the actual number of bytes received. On output the
  3230. number of bytes for the current packet. If 0 on output,
  3231. we did not have a complete packet. Undefined on failure.
  3232. Return Value:
  3233. --*/
  3234. {
  3235. BYTE *LocalReadBuffer;
  3236. ULONG MessageSize;
  3237. ULONG ExtraSize;
  3238. ULONG AllocSize;
  3239. BYTE *NewBuffer;
  3240. BOOL DoNotComplete;
  3241. ULONG LocalBufferLength = *BufferLength;
  3242. DoNotComplete = FALSE;
  3243. if (EventStatus == RPC_S_OK)
  3244. {
  3245. ASSERT(pReadBuffer);
  3246. LocalBufferLength += iLastRead;
  3247. ASSERT(LocalBufferLength <= MaxReadBuffer);
  3248. if (LocalBufferLength < sizeof(CONN_RPC_HEADER))
  3249. {
  3250. // Not a whole header, resubmit the read and continue.
  3251. iLastRead = LocalBufferLength;
  3252. EventStatus = PostReceive();
  3253. if (EventStatus == RPC_S_OK)
  3254. DoNotComplete = TRUE;
  3255. else
  3256. LocalReadBuffer = NULL;
  3257. }
  3258. else
  3259. {
  3260. MessageSize = MessageLength((PCONN_RPC_HEADER)pReadBuffer);
  3261. if (MessageSize < sizeof(CONN_RPC_HEADER))
  3262. {
  3263. ASSERT(MessageSize >= sizeof(CONN_RPC_HEADER));
  3264. EventStatus = RPC_P_RECEIVE_FAILED;
  3265. }
  3266. else if (LocalBufferLength == MessageSize)
  3267. {
  3268. // All set, have a complete request.
  3269. LocalReadBuffer = pReadBuffer;
  3270. LocalBufferLength = MessageSize;
  3271. iLastRead = 0;
  3272. pReadBuffer = 0;
  3273. }
  3274. else if (MessageSize > LocalBufferLength)
  3275. {
  3276. // Don't have a complete message, realloc if needed and
  3277. // resubmit a read for the remaining bytes.
  3278. if (MaxReadBuffer < MessageSize)
  3279. {
  3280. // Buffer too small for the message.
  3281. EventStatus = TransConnectionReallocPacket(NULL,
  3282. &pReadBuffer,
  3283. LocalBufferLength,
  3284. MessageSize);
  3285. if (EventStatus == RPC_S_OK)
  3286. {
  3287. // increase the post size, but not if we are in paged
  3288. // buffer mode.
  3289. if (fPagedBCacheMode == FALSE)
  3290. iPostSize = MessageSize;
  3291. }
  3292. }
  3293. if (EventStatus == RPC_S_OK)
  3294. {
  3295. // Setup to receive exactly the remaining bytes of the message.
  3296. iLastRead = LocalBufferLength;
  3297. MaxReadBuffer = MessageSize;
  3298. EventStatus = PostReceive();
  3299. if (EventStatus == RPC_S_OK)
  3300. DoNotComplete = TRUE;
  3301. else
  3302. LocalReadBuffer = NULL;
  3303. }
  3304. }
  3305. else
  3306. {
  3307. // Coalesced read, save extra data. Very uncommon
  3308. ASSERT(LocalBufferLength > MessageSize);
  3309. // The first message and size will be returned
  3310. LocalReadBuffer = pReadBuffer;
  3311. ExtraSize = LocalBufferLength - MessageSize;
  3312. LocalBufferLength = MessageSize;
  3313. // Try to find a good size of the extra PDU(s)
  3314. if (ExtraSize < sizeof(CONN_RPC_HEADER))
  3315. {
  3316. // Not a whole header, we'll assume gPostSize;
  3317. AllocSize = gPostSize;
  3318. }
  3319. else
  3320. {
  3321. #ifdef _M_IA64
  3322. // The first packet may not contain a number of bytes
  3323. // that align the second on an 8-byte boundary. Hence, the
  3324. // structure may end up unaligned.
  3325. AllocSize = MessageLengthUnaligned((PCONN_RPC_HEADER)(pReadBuffer
  3326. + MessageSize));
  3327. #else
  3328. AllocSize = MessageLength((PCONN_RPC_HEADER)(pReadBuffer
  3329. + MessageSize));
  3330. #endif
  3331. }
  3332. if (AllocSize < ExtraSize)
  3333. {
  3334. // This can happen if there are more than two PDUs coalesced together
  3335. // in the buffer. Or if the PDU is invalid. Or if the iPostSize is
  3336. // smaller than the next PDU.
  3337. AllocSize = ExtraSize;
  3338. }
  3339. // Allocate a new buffer to save the extra data for the next read.
  3340. NewBuffer = (BYTE *)RpcAllocateBuffer(AllocSize);
  3341. if (0 == NewBuffer)
  3342. {
  3343. // We have a complete request. We could process the request and
  3344. // close the connection only after trying to send the reply.
  3345. LocalReadBuffer = NULL;
  3346. LocalBufferLength = 0;
  3347. EventStatus = RPC_S_OUT_OF_MEMORY;
  3348. }
  3349. else
  3350. {
  3351. ASSERT(pReadBuffer);
  3352. // Save away extra data for the next receive
  3353. RpcpMemoryCopy(NewBuffer,
  3354. pReadBuffer + LocalBufferLength,
  3355. ExtraSize);
  3356. pReadBuffer = NewBuffer;
  3357. iLastRead = ExtraSize;
  3358. MaxReadBuffer = AllocSize;
  3359. ASSERT(iLastRead <= MaxReadBuffer);
  3360. EventStatus = RPC_S_OK;
  3361. }
  3362. }
  3363. }
  3364. }
  3365. else
  3366. {
  3367. // in failure cases we keep the buffer. We will
  3368. // free it on Abort.
  3369. LocalReadBuffer = NULL;
  3370. }
  3371. if (DoNotComplete == FALSE)
  3372. {
  3373. *Buffer = LocalReadBuffer;
  3374. *BufferLength = LocalBufferLength;
  3375. EventStatus = UpperLayer->ReceiveComplete(EventStatus,
  3376. TrafficType,
  3377. LocalReadBuffer,
  3378. LocalBufferLength
  3379. );
  3380. return AsyncCompleteHelper(EventStatus);
  3381. // don't touch the this pointer after AsyncCompleteHelper.
  3382. // It could be gone.
  3383. }
  3384. else
  3385. {
  3386. *Buffer = NULL;
  3387. *BufferLength = 0;
  3388. return RPC_S_OK;
  3389. }
  3390. }
  3391. /*********************************************************************
  3392. HTTP2WinHttpTransportChannel
  3393. *********************************************************************/
  3394. // our public constants are aligned with HTTP constants. Even though it is
  3395. // unlikely for either to change, make sure they don't. If they do, we need
  3396. // a remapping function as we use them interchangeably in the code
  3397. C_ASSERT(WINHTTP_AUTH_SCHEME_BASIC == RPC_C_HTTP_AUTHN_SCHEME_BASIC);
  3398. C_ASSERT(WINHTTP_AUTH_SCHEME_NTLM == RPC_C_HTTP_AUTHN_SCHEME_NTLM);
  3399. C_ASSERT(WINHTTP_AUTH_SCHEME_PASSPORT == RPC_C_HTTP_AUTHN_SCHEME_PASSPORT);
  3400. C_ASSERT(WINHTTP_AUTH_SCHEME_DIGEST == RPC_C_HTTP_AUTHN_SCHEME_DIGEST);
  3401. C_ASSERT(WINHTTP_AUTH_SCHEME_NEGOTIATE == RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE);
  3402. HTTP2WinHttpTransportChannel::HTTP2WinHttpTransportChannel (
  3403. OUT RPC_STATUS *RpcStatus
  3404. ) : Mutex (RpcStatus)
  3405. /*++
  3406. Routine Description:
  3407. HTTP2WinHttpTransportChannel constructor.
  3408. Arguments:
  3409. RpcStatus - on output will contain the result of the
  3410. initialization.
  3411. Return Value:
  3412. --*/
  3413. {
  3414. hSession = NULL;
  3415. hConnect = NULL;
  3416. hRequest = NULL;
  3417. SyncEvent = NULL;
  3418. RpcpInitializeListHead(&BufferQueueHead);
  3419. pReadBuffer = NULL;
  3420. MaxReadBuffer = 0;
  3421. iLastRead = 0;
  3422. SendsPending = 0;
  3423. State = whtcsNew;
  3424. AsyncError = RPC_S_INTERNAL_ERROR;
  3425. HttpCredentials = NULL;
  3426. KeepAlive = FALSE;
  3427. CredentialsSetForScheme = 0;
  3428. PreviousRequestContentLength = -1;
  3429. ChosenAuthScheme = 0;
  3430. DelayedReceiveTrafficType = http2ttNone;
  3431. CurrentSendContext = NULL;
  3432. }
  3433. const RPC_CHAR ContentLengthHeader[] = L"Content-Length:";
  3434. RPC_STATUS HTTP2WinHttpTransportChannel::Open (
  3435. IN HTTPResolverHint *Hint,
  3436. IN const RPC_CHAR *Verb,
  3437. IN const RPC_CHAR *Url,
  3438. IN const RPC_CHAR *AcceptType,
  3439. IN ULONG ContentLength,
  3440. IN ULONG CallTimeout,
  3441. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  3442. IN ULONG ChosenAuthScheme,
  3443. IN const BYTE *AdditionalData OPTIONAL
  3444. )
  3445. /*++
  3446. Routine Description:
  3447. Opens the connection to the proxy. We know that a failed Open
  3448. will be followed by Abort.
  3449. Arguments:
  3450. Hint - the resolver hint
  3451. Verb - the verb to use.
  3452. Url - the url to connect to.
  3453. AcceptType - string representation of the accept type.
  3454. ContentLength - the content length for the request (i.e. the
  3455. channel lifetime)
  3456. CallTimeout - the timeout for the operation
  3457. HttpCredentials - the HTTP transport credentials
  3458. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  3459. AdditionalData - additional data to send with the header. Must be set iff
  3460. AdditionalDataLength != 0
  3461. Return Value:
  3462. RPC_S_OK or RPC_S_* error.
  3463. --*/
  3464. {
  3465. BOOL HttpResult = FALSE;
  3466. DWORD dwReadBufferSizeSize = sizeof(ULONG);
  3467. ULONG WinHttpAccessType;
  3468. LPCWSTR AcceptTypes[2];
  3469. ULONG LastError;
  3470. RPC_CHAR *UnicodeString;
  3471. ULONG UnicodeStringSize; // in characters including null terminated NULL
  3472. RPC_STATUS RpcStatus;
  3473. ULONG FlagsToAdd;
  3474. RPC_HTTP_TRANSPORT_CREDENTIALS_W *TransHttpCredentials;
  3475. ULONG AdditionalDataLengthToUse;
  3476. ULONG ContentLengthToUse;
  3477. ULONG BytesAvailable;
  3478. RPC_CHAR ContentLengthString[40]; // enough space for "Content-Length:" + channel lifetime
  3479. BOOL IsInChannel;
  3480. BOOL TestOverrideUsed;
  3481. RPC_CHAR *User;
  3482. RPC_CHAR *Password;
  3483. RPC_CHAR *Domain;
  3484. HANDLE LocalEvent = NULL;
  3485. ULONG SecLevel;
  3486. BOOL LanManHashDisabled;
  3487. ULONG DomainAndUserLength; // length in characters not including null terminator
  3488. ULONG DomainLength; // length in characters not including null terminator
  3489. ULONG UserLength; // length in characters not including null terminator
  3490. RPC_CHAR *DomainAndUserName;
  3491. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3492. (ULONG_PTR)ContentLength);
  3493. this->HttpCredentials = HttpCredentials;
  3494. // Open can be called multiple times to send opening requests.
  3495. // Make sure general initialization is done only once.
  3496. if (hSession == NULL)
  3497. {
  3498. ASSERT(hConnect == NULL);
  3499. State = whtcsOpeningRequest;
  3500. ASSERT(Hint->AccessType != rpcpatUnknown);
  3501. if (Hint->AccessType == rpcpatDirect)
  3502. {
  3503. WinHttpAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  3504. UnicodeString = NULL;
  3505. UnicodeStringSize = 0;
  3506. }
  3507. else
  3508. {
  3509. WinHttpAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  3510. UnicodeStringSize = RpcpStringLengthA(Hint->HTTPProxy) + 1;
  3511. UnicodeString = new RPC_CHAR [UnicodeStringSize];
  3512. if (UnicodeString == NULL)
  3513. {
  3514. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3515. RPC_S_OUT_OF_MEMORY);
  3516. return RPC_S_OUT_OF_MEMORY;
  3517. }
  3518. FullAnsiToUnicode(Hint->HTTPProxy, UnicodeString);
  3519. }
  3520. // Use WinHttpOpen to obtain a session handle.
  3521. hSession = WinHttpOpenImp( L"MSRPC",
  3522. WinHttpAccessType,
  3523. UnicodeString,
  3524. WINHTTP_NO_PROXY_BYPASS,
  3525. WINHTTP_FLAG_ASYNC
  3526. );
  3527. if (!hSession)
  3528. {
  3529. VALIDATE(GetLastError())
  3530. {
  3531. ERROR_NOT_ENOUGH_MEMORY
  3532. } END_VALIDATE;
  3533. if (UnicodeString)
  3534. delete [] UnicodeString;
  3535. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3536. RPC_S_OUT_OF_MEMORY);
  3537. return RPC_S_OUT_OF_MEMORY;
  3538. }
  3539. // Set the callback to be used by WinHttp to notify us of IO completion.
  3540. WinHttpSetStatusCallbackImp( hSession,
  3541. WinHttpCallback,
  3542. WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
  3543. NULL // Reserved: must be NULL
  3544. );
  3545. // Set the communication timeout.
  3546. HttpResult = WinHttpSetOptionImp( hSession,
  3547. WINHTTP_OPTION_CONNECT_TIMEOUT,
  3548. (LPVOID)&CallTimeout,
  3549. sizeof(ULONG)
  3550. );
  3551. // this function cannot fail unless we give it invalid parameters
  3552. ASSERT(HttpResult == TRUE);
  3553. // Set the send/receive timeout.
  3554. CallTimeout = 30 * 60 * 1000;
  3555. HttpResult = WinHttpSetOptionImp( hSession,
  3556. WINHTTP_OPTION_SEND_TIMEOUT,
  3557. (LPVOID)&CallTimeout,
  3558. sizeof(ULONG)
  3559. );
  3560. // this function cannot fail unless we give it invalid parameters
  3561. ASSERT(HttpResult == TRUE);
  3562. CallTimeout = 30 * 60 * 1000;
  3563. HttpResult = WinHttpSetOptionImp( hSession,
  3564. WINHTTP_OPTION_RECEIVE_TIMEOUT,
  3565. (LPVOID)&CallTimeout,
  3566. sizeof(ULONG)
  3567. );
  3568. // this function cannot fail unless we give it invalid parameters
  3569. ASSERT(HttpResult == TRUE);
  3570. RpcStatus = TopChannel->IsInChannel(&IsInChannel);
  3571. // this cannot fail here. We're opening the channel
  3572. ASSERT(RpcStatus == RPC_S_OK);
  3573. if (IsInChannel && InChannelTargetTestOverride)
  3574. {
  3575. TestOverrideUsed = TRUE;
  3576. UnicodeString = InChannelTargetTestOverride;
  3577. }
  3578. else if (!IsInChannel && OutChannelTargetTestOverride)
  3579. {
  3580. TestOverrideUsed = TRUE;
  3581. UnicodeString = OutChannelTargetTestOverride;
  3582. }
  3583. else
  3584. {
  3585. TestOverrideUsed = FALSE;
  3586. if (Hint->ProxyNameLength + 1 > UnicodeStringSize)
  3587. {
  3588. if (UnicodeString)
  3589. delete [] UnicodeString;
  3590. UnicodeString = new RPC_CHAR [Hint->ProxyNameLength + 1];
  3591. if (UnicodeString == NULL)
  3592. {
  3593. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3594. RPC_S_OUT_OF_MEMORY);
  3595. return RPC_S_OUT_OF_MEMORY;
  3596. }
  3597. }
  3598. FullAnsiToUnicode(Hint->RpcProxy, UnicodeString);
  3599. }
  3600. // Specify an HTTP server to talk to.
  3601. hConnect = WinHttpConnectImp( hSession,
  3602. UnicodeString,
  3603. Hint->RpcProxyPort,
  3604. NULL // Reserved: must be NULL
  3605. );
  3606. if (TestOverrideUsed == FALSE)
  3607. delete [] UnicodeString;
  3608. if (!hConnect)
  3609. {
  3610. VALIDATE(GetLastError())
  3611. {
  3612. ERROR_NOT_ENOUGH_MEMORY
  3613. } END_VALIDATE;
  3614. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3615. RPC_S_OUT_OF_MEMORY);
  3616. return RPC_S_OUT_OF_MEMORY;
  3617. }
  3618. // Create an HTTP Request handle.
  3619. AcceptTypes[0] = AcceptType;
  3620. AcceptTypes[1] = NULL;
  3621. if (HttpCredentials && (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL))
  3622. FlagsToAdd = WINHTTP_FLAG_SECURE;
  3623. else
  3624. FlagsToAdd = 0;
  3625. hRequest = WinHttpOpenRequestImp( hConnect,
  3626. Verb,
  3627. Url,
  3628. NULL, // Version: HTTP/1.1
  3629. WINHTTP_NO_REFERER, // Referer: none
  3630. AcceptTypes, // AcceptTypes: all
  3631. WINHTTP_FLAG_REFRESH | FlagsToAdd // Flags
  3632. );
  3633. if (!hRequest)
  3634. {
  3635. VALIDATE(GetLastError())
  3636. {
  3637. ERROR_NOT_ENOUGH_MEMORY
  3638. } END_VALIDATE;
  3639. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3640. RPC_S_OUT_OF_MEMORY);
  3641. return RPC_S_OUT_OF_MEMORY;
  3642. }
  3643. // Query the optimal read buffer size.
  3644. // We can only query the buffer size from the request handle.
  3645. HttpResult = WinHttpQueryOptionImp( hRequest,
  3646. WINHTTP_OPTION_READ_BUFFER_SIZE,
  3647. (LPVOID)&iPostSize,
  3648. &dwReadBufferSizeSize
  3649. );
  3650. // this cannot fail unless we give it invalid parameters
  3651. ASSERT (HttpResult == TRUE);
  3652. ASSERT(dwReadBufferSizeSize != 0);
  3653. }
  3654. else
  3655. {
  3656. ASSERT(hConnect != NULL);
  3657. ASSERT(hRequest != NULL);
  3658. }
  3659. // do we have a winner? If yes, have we already set the credentials for
  3660. // this scheme? Note that for Basic we need to set them every time.
  3661. if (ChosenAuthScheme
  3662. &&
  3663. (
  3664. (ChosenAuthScheme != CredentialsSetForScheme)
  3665. ||
  3666. (ChosenAuthScheme == RPC_C_HTTP_AUTHN_SCHEME_BASIC)
  3667. )
  3668. )
  3669. {
  3670. // yes. Just use it
  3671. ASSERT(HttpCredentials);
  3672. // we will set the auto logon policy to low (i.e. send NTLM credentials)
  3673. // in two cases. One is if SSL & mutual auth are used. The second is if LM
  3674. // hash is disabled (i.e. the NTLM negotiate leg does not expose user credentials)
  3675. // first, check whether the hash is enabled
  3676. RpcStatus = IsLanManHashDisabled(&LanManHashDisabled);
  3677. if (RpcStatus != RPC_S_OK)
  3678. {
  3679. VALIDATE(RpcStatus)
  3680. {
  3681. RPC_S_OUT_OF_MEMORY
  3682. } END_VALIDATE;
  3683. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3684. RpcStatus);
  3685. return RpcStatus;
  3686. }
  3687. if (
  3688. (
  3689. (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  3690. &&
  3691. (HttpCredentials->ServerCertificateSubject)
  3692. )
  3693. ||
  3694. (LanManHashDisabled)
  3695. )
  3696. {
  3697. SecLevel = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
  3698. HttpResult = WinHttpSetOptionImp( hRequest,
  3699. WINHTTP_OPTION_AUTOLOGON_POLICY,
  3700. &SecLevel,
  3701. sizeof(ULONG)
  3702. );
  3703. // this function cannot fail unless we give it invalid parameters
  3704. ASSERT(HttpResult == TRUE);
  3705. }
  3706. TransHttpCredentials = I_RpcTransGetHttpCredentials(HttpCredentials);
  3707. if (TransHttpCredentials == NULL)
  3708. {
  3709. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3710. RPC_S_OUT_OF_MEMORY);
  3711. return RPC_S_OUT_OF_MEMORY;
  3712. }
  3713. if (TransHttpCredentials->TransportCredentials)
  3714. {
  3715. User = TransHttpCredentials->TransportCredentials->User;
  3716. Domain = TransHttpCredentials->TransportCredentials->Domain;
  3717. Password = TransHttpCredentials->TransportCredentials->Password;
  3718. DomainLength = RpcpStringLength(Domain);
  3719. UserLength = RpcpStringLength(User);
  3720. // add 1 for '\'
  3721. DomainAndUserLength = DomainLength + 1 + UserLength;
  3722. // add 1 for terminator
  3723. DomainAndUserName = new RPC_CHAR [DomainAndUserLength + 1];
  3724. if (DomainAndUserName == NULL)
  3725. {
  3726. I_RpcTransFreeHttpCredentials(TransHttpCredentials);
  3727. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3728. RPC_S_OUT_OF_MEMORY);
  3729. return RPC_S_OUT_OF_MEMORY;
  3730. }
  3731. RpcpMemoryCopy(DomainAndUserName, Domain, DomainLength * 2);
  3732. DomainAndUserName[DomainLength] = '\\';
  3733. RpcpMemoryCopy(DomainAndUserName + DomainLength + 1, User, UserLength * 2);
  3734. DomainAndUserName[DomainLength + 1 + UserLength] = '\0';
  3735. }
  3736. else
  3737. {
  3738. if (ChosenAuthScheme == RPC_C_HTTP_AUTHN_SCHEME_BASIC)
  3739. {
  3740. // Basic does not support implicit credentials
  3741. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3742. RPC_S_ACCESS_DENIED);
  3743. return RPC_S_ACCESS_DENIED;
  3744. }
  3745. User = NULL;
  3746. Password = NULL;
  3747. DomainAndUserName = NULL;
  3748. }
  3749. HttpResult = WinHttpSetCredentialsImp (hRequest,
  3750. WINHTTP_AUTH_TARGET_SERVER,
  3751. ChosenAuthScheme,
  3752. DomainAndUserName,
  3753. Password,
  3754. NULL
  3755. );
  3756. // success or error, free the domain and user name
  3757. if (DomainAndUserName)
  3758. {
  3759. // technically speaking, we don't have to zero out user and domain name
  3760. // since they are not secret. However, the way the heap works it is likely
  3761. // that they will be next to our credentials, which are not encrypted very
  3762. // strongly. So wipe out the domain and user to prevent an attacker from
  3763. // using them to locate the credentials
  3764. RpcpMemorySet(DomainAndUserName, 0, DomainAndUserLength);
  3765. delete [] DomainAndUserName;
  3766. }
  3767. if (!HttpResult)
  3768. {
  3769. LastError = GetLastError();
  3770. VALIDATE(LastError)
  3771. {
  3772. ERROR_NOT_ENOUGH_MEMORY
  3773. } END_VALIDATE;
  3774. }
  3775. I_RpcTransFreeHttpCredentials(TransHttpCredentials);
  3776. if (!HttpResult)
  3777. {
  3778. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3779. RPC_S_OUT_OF_MEMORY);
  3780. return RPC_S_OUT_OF_MEMORY;
  3781. }
  3782. // remember that we have already set credentials for this scheme
  3783. CredentialsSetForScheme = ChosenAuthScheme;
  3784. }
  3785. LocalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  3786. if (LocalEvent == NULL)
  3787. {
  3788. RpcStatus = RPC_S_OUT_OF_MEMORY;
  3789. goto CleanupAndExit;
  3790. }
  3791. SyncEvent = LocalEvent;
  3792. LastError = RPC_S_OK;
  3793. // Send a Request.
  3794. if (AdditionalData)
  3795. {
  3796. // if additional data to append, send them immediately
  3797. AdditionalDataLengthToUse = ContentLength;
  3798. ContentLengthToUse = ContentLength;
  3799. }
  3800. else
  3801. {
  3802. AdditionalDataLengthToUse = 0;
  3803. ContentLengthToUse = ContentLength;
  3804. }
  3805. if ((PreviousRequestContentLength != -1) && (ContentLengthToUse != PreviousRequestContentLength))
  3806. {
  3807. // WinHttp normally doesn't update the content-length header if you reuse the
  3808. // request. Do that now.
  3809. RpcpMemoryCopy(ContentLengthString, ContentLengthHeader, sizeof(ContentLengthHeader));
  3810. RpcpItow(ContentLengthToUse, ContentLengthString + sizeof(ContentLengthHeader), 10);
  3811. HttpResult = WinHttpAddRequestHeadersImp (hRequest,
  3812. ContentLengthString,
  3813. -1, // dwHeadersLength - have WinHttp calculate it
  3814. WINHTTP_ADDREQ_FLAG_REPLACE
  3815. );
  3816. if (!HttpResult)
  3817. {
  3818. LastError = GetLastError();
  3819. VALIDATE(LastError)
  3820. {
  3821. ERROR_NOT_ENOUGH_MEMORY
  3822. } END_VALIDATE;
  3823. RpcStatus = LastError;
  3824. goto CleanupAndExit;
  3825. }
  3826. }
  3827. PreviousRequestContentLength = ContentLengthToUse;
  3828. State = whtcsSendingRequest;
  3829. HttpResult = WinHttpSendRequestImp( hRequest,
  3830. WINHTTP_NO_ADDITIONAL_HEADERS, // Additional headers
  3831. 0, // Length of the additional headers
  3832. (LPVOID)AdditionalData, // Optional data to append to the request
  3833. AdditionalDataLengthToUse, // Length of the optional data
  3834. ContentLengthToUse, // Length in bytes of the total data sent
  3835. (DWORD_PTR) this // Application-specified context for this request
  3836. );
  3837. if (!HttpResult)
  3838. {
  3839. SyncEvent = NULL;
  3840. LastError = GetLastError();
  3841. }
  3842. else
  3843. {
  3844. // Sleep waiting for the send request to be completed.
  3845. LastError = WaitForSingleObject(SyncEvent, INFINITE);
  3846. SyncEvent = NULL;
  3847. ASSERT(State == whtcsSentRequest);
  3848. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  3849. LastError = AsyncError;
  3850. AsyncError = RPC_S_INTERNAL_ERROR;
  3851. }
  3852. if (LastError != RPC_S_OK)
  3853. {
  3854. VALIDATE(LastError)
  3855. {
  3856. ERROR_WINHTTP_CANNOT_CONNECT,
  3857. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  3858. ERROR_WINHTTP_CONNECTION_ERROR,
  3859. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  3860. ERROR_WINHTTP_INVALID_URL,
  3861. ERROR_WINHTTP_LOGIN_FAILURE,
  3862. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  3863. ERROR_WINHTTP_OUT_OF_HANDLES,
  3864. ERROR_WINHTTP_REDIRECT_FAILED,
  3865. ERROR_WINHTTP_RESEND_REQUEST,
  3866. ERROR_WINHTTP_SECURE_FAILURE,
  3867. ERROR_WINHTTP_SHUTDOWN,
  3868. ERROR_WINHTTP_TIMEOUT,
  3869. ERROR_NOT_ENOUGH_MEMORY,
  3870. ERROR_NOT_SUPPORTED,
  3871. RPC_P_RECEIVE_FAILED,
  3872. RPC_P_SEND_FAILED,
  3873. RPC_S_OUT_OF_MEMORY,
  3874. RPC_S_ACCESS_DENIED,
  3875. ERROR_NO_SYSTEM_RESOURCES,
  3876. ERROR_COMMITMENT_LIMIT
  3877. } END_VALIDATE;
  3878. switch (LastError)
  3879. {
  3880. case ERROR_WINHTTP_CANNOT_CONNECT:
  3881. case ERROR_WINHTTP_CONNECTION_ERROR:
  3882. case ERROR_WINHTTP_INVALID_URL:
  3883. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  3884. case ERROR_WINHTTP_REDIRECT_FAILED:
  3885. case ERROR_WINHTTP_RESEND_REQUEST:
  3886. case ERROR_WINHTTP_SHUTDOWN:
  3887. case RPC_P_RECEIVE_FAILED:
  3888. case RPC_P_SEND_FAILED:
  3889. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  3890. break;
  3891. case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
  3892. case ERROR_WINHTTP_SECURE_FAILURE:
  3893. RpcStatus = RPC_S_ACCESS_DENIED;
  3894. break;
  3895. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  3896. RpcStatus = RPC_S_PROTOCOL_ERROR;
  3897. break;
  3898. case ERROR_WINHTTP_OUT_OF_HANDLES:
  3899. case ERROR_NOT_ENOUGH_MEMORY:
  3900. case RPC_S_OUT_OF_MEMORY:
  3901. case ERROR_NO_SYSTEM_RESOURCES:
  3902. case ERROR_COMMITMENT_LIMIT:
  3903. RpcStatus = RPC_S_OUT_OF_MEMORY;
  3904. break;
  3905. case ERROR_NOT_SUPPORTED:
  3906. RpcStatus = RPC_S_CANNOT_SUPPORT;
  3907. break;
  3908. case ERROR_WINHTTP_TIMEOUT:
  3909. RpcStatus = RPC_S_CALL_CANCELLED;
  3910. break;
  3911. default:
  3912. // acess denied doesn't get remapped
  3913. ASSERT(LastError == RPC_S_ACCESS_DENIED);
  3914. RpcStatus = LastError;
  3915. break;
  3916. }
  3917. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3918. RpcStatus);
  3919. goto CleanupAndExit;
  3920. }
  3921. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3922. RPC_S_OK);
  3923. RpcStatus = RPC_S_OK;
  3924. CleanupAndExit:
  3925. if (LocalEvent != NULL)
  3926. CloseHandle(LocalEvent);
  3927. return RpcStatus;
  3928. }
  3929. RPC_STATUS HTTP2WinHttpTransportChannel::Send (
  3930. IN OUT HTTP2SendContext *SendContext
  3931. )
  3932. /*++
  3933. Routine Description:
  3934. Send request
  3935. Arguments:
  3936. SendContext - the send context
  3937. Return Value:
  3938. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3939. --*/
  3940. {
  3941. BOOL HttpResult = TRUE;
  3942. ULONG LastError;
  3943. RPC_STATUS RpcStatus;
  3944. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3945. (ULONG_PTR)SendContext);
  3946. Mutex.Request();
  3947. SendsPending ++;
  3948. ASSERT(SendsPending >= 0);
  3949. if (SendsPending > 1)
  3950. {
  3951. // queue and exit
  3952. SendContext->SetListEntryUsed();
  3953. RpcpInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  3954. Mutex.Clear();
  3955. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3956. SendsPending);
  3957. return RPC_S_OK;
  3958. }
  3959. Mutex.Clear();
  3960. ASSERT(State == whtcsSentRequest);
  3961. State = whtcsWriting;
  3962. CurrentSendContext = SendContext;
  3963. HttpResult = WinHttpWriteDataImp(hRequest,
  3964. SendContext->pWriteBuffer,
  3965. SendContext->maxWriteBuffer,
  3966. &NumberOfBytesTransferred
  3967. );
  3968. if (HttpResult == FALSE)
  3969. {
  3970. LastError = GetLastError();
  3971. VALIDATE(LastError)
  3972. {
  3973. ERROR_WINHTTP_CONNECTION_ERROR,
  3974. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  3975. ERROR_WINHTTP_RESEND_REQUEST,
  3976. ERROR_WINHTTP_SHUTDOWN
  3977. } END_VALIDATE;
  3978. RpcStatus = RPC_P_SEND_FAILED;
  3979. }
  3980. else
  3981. RpcStatus = RPC_S_OK;
  3982. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3983. RpcStatus);
  3984. return RpcStatus;
  3985. };
  3986. RPC_STATUS HTTP2WinHttpTransportChannel::Receive (
  3987. IN HTTP2TrafficType TrafficType
  3988. )
  3989. /*++
  3990. Routine Description:
  3991. Receive request
  3992. Arguments:
  3993. TrafficType - the type of traffic we want to receive
  3994. Return Value:
  3995. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3996. --*/
  3997. {
  3998. BOOL HttpResult;
  3999. ULONG LastError;
  4000. RPC_STATUS RpcStatus;
  4001. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4002. TrafficType);
  4003. //
  4004. // Before we can do any receives, we need to do a WinHttpReceiveResponse
  4005. // if it has not been issued yet.
  4006. //
  4007. // This call only needs to be done before the first Receive.
  4008. //
  4009. if (State != whtcsReceivedResponse)
  4010. {
  4011. Mutex.Request();
  4012. // if there are still sends, we have indicated our
  4013. // traffic type in the DelayedReceiveTrafficType.
  4014. // Just exit, and the last send will do the receive
  4015. // work.
  4016. if (SendsPending > 0)
  4017. {
  4018. if (TrafficType == http2ttRTS)
  4019. DelayedReceiveTrafficType = http2ttRTSWithSpecialBit;
  4020. else if (TrafficType == http2ttData)
  4021. DelayedReceiveTrafficType = http2ttDataWithSpecialBit;
  4022. else
  4023. {
  4024. ASSERT(TrafficType == http2ttRaw);
  4025. DelayedReceiveTrafficType = http2ttRawWithSpecialBit;
  4026. }
  4027. Mutex.Clear();
  4028. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4029. SendsPending);
  4030. return RPC_S_OK;
  4031. }
  4032. Mutex.Clear();
  4033. DelayedReceiveTrafficType = TrafficType;
  4034. ASSERT(State == whtcsSentRequest);
  4035. State = whtcsReceivingResponse;
  4036. HttpResult = WinHttpReceiveResponseImp(hRequest, NULL);
  4037. // If the function returned FALSE, then it has failed syncronously.
  4038. if (!HttpResult)
  4039. {
  4040. DelayedReceiveTrafficType = http2ttNone;
  4041. LastError = GetLastError();
  4042. VALIDATE(LastError)
  4043. {
  4044. ERROR_WINHTTP_CANNOT_CONNECT,
  4045. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  4046. ERROR_WINHTTP_CONNECTION_ERROR,
  4047. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4048. ERROR_WINHTTP_INVALID_URL,
  4049. ERROR_WINHTTP_LOGIN_FAILURE,
  4050. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  4051. ERROR_WINHTTP_OUT_OF_HANDLES,
  4052. ERROR_WINHTTP_REDIRECT_FAILED,
  4053. ERROR_WINHTTP_RESEND_REQUEST,
  4054. ERROR_WINHTTP_SECURE_FAILURE,
  4055. ERROR_WINHTTP_SHUTDOWN,
  4056. ERROR_WINHTTP_TIMEOUT,
  4057. ERROR_NOT_SUPPORTED
  4058. } END_VALIDATE;
  4059. switch (LastError)
  4060. {
  4061. case ERROR_WINHTTP_CONNECTION_ERROR:
  4062. case ERROR_WINHTTP_REDIRECT_FAILED:
  4063. case ERROR_WINHTTP_RESEND_REQUEST:
  4064. case ERROR_WINHTTP_SHUTDOWN:
  4065. case ERROR_WINHTTP_SECURE_FAILURE:
  4066. RpcStatus = RPC_P_RECEIVE_FAILED;
  4067. break;
  4068. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  4069. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4070. break;
  4071. case ERROR_NOT_SUPPORTED:
  4072. RpcStatus = RPC_S_CANNOT_SUPPORT;
  4073. break;
  4074. case ERROR_WINHTTP_TIMEOUT:
  4075. RpcStatus = RPC_S_CALL_CANCELLED;
  4076. break;
  4077. default:
  4078. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4079. break;
  4080. }
  4081. VALIDATE(RpcStatus)
  4082. {
  4083. RPC_S_OUT_OF_MEMORY,
  4084. RPC_S_OUT_OF_RESOURCES,
  4085. RPC_P_RECEIVE_FAILED,
  4086. RPC_S_CALL_CANCELLED,
  4087. RPC_P_SEND_FAILED,
  4088. RPC_P_CONNECTION_SHUTDOWN,
  4089. RPC_P_TIMEOUT
  4090. } END_VALIDATE;
  4091. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4092. RpcStatus);
  4093. return RpcStatus;
  4094. }
  4095. else
  4096. {
  4097. // If the function returned TRUE, then it will complete asyncronously.
  4098. // We should return. All additional work will be done on a separate thread
  4099. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4100. RPC_S_OK);
  4101. return RPC_S_OK;
  4102. }
  4103. }
  4104. RpcStatus = HTTP2FragmentReceiver::Receive(TrafficType);
  4105. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4106. RpcStatus);
  4107. return RpcStatus;
  4108. };
  4109. RPC_STATUS HTTP2WinHttpTransportChannel::SendComplete (
  4110. IN RPC_STATUS EventStatus,
  4111. IN OUT HTTP2SendContext *SendContext
  4112. )
  4113. /*++
  4114. Routine Description:
  4115. Send complete notification
  4116. Arguments:
  4117. EventStatus - status of the operation
  4118. SendContext - the send context
  4119. Return Value:
  4120. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  4121. --*/
  4122. {
  4123. HTTP2SendContext *QueuedSendContext;
  4124. LIST_ENTRY *QueuedListEntry;
  4125. ULONG LocalSendsPending;
  4126. BOOL HttpResult;
  4127. ULONG LastError;
  4128. RPC_STATUS RpcStatus;
  4129. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4130. EventStatus);
  4131. CurrentSendContext = NULL;
  4132. Mutex.Request();
  4133. // decrement this in advance so that if we post another send on send
  4134. // complete, it doesn't get queued
  4135. LocalSendsPending = -- SendsPending;
  4136. ASSERT(SendsPending >= 0);
  4137. Mutex.Clear();
  4138. // If we are processing a failed send-complete, this call may abort
  4139. // the channels and complete pending sends.
  4140. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  4141. if ((EventStatus == RPC_S_OK)
  4142. || (EventStatus == RPC_P_PACKET_CONSUMED) )
  4143. {
  4144. QueuedSendContext = NULL;
  4145. // Check if we have a queued send context.
  4146. // Because we pre-decremented SendsPending, we have "borrowed"
  4147. // a count and there is a queued context iff the count is above 0.
  4148. if (LocalSendsPending > 0)
  4149. {
  4150. Mutex.Request();
  4151. QueuedListEntry = RpcpRemoveHeadList(&BufferQueueHead);
  4152. ASSERT(QueuedListEntry);
  4153. ASSERT(QueuedListEntry != &BufferQueueHead);
  4154. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  4155. Mutex.Clear();
  4156. QueuedSendContext->SetListEntryUnused();
  4157. }
  4158. if (QueuedSendContext)
  4159. {
  4160. ASSERT(State == whtcsSentRequest);
  4161. State = whtcsWriting;
  4162. // need to synchronize with aborts (rule 9)
  4163. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4164. CurrentSendContext = QueuedSendContext;
  4165. NumberOfBytesTransferred = QueuedSendContext->maxWriteBuffer;
  4166. if (RpcStatus == RPC_S_OK)
  4167. {
  4168. HttpResult = WinHttpWriteDataImp(hRequest,
  4169. QueuedSendContext->pWriteBuffer,
  4170. QueuedSendContext->maxWriteBuffer,
  4171. &NumberOfBytesTransferred
  4172. );
  4173. TopChannel->FinishSubmitAsync();
  4174. if (HttpResult == FALSE)
  4175. {
  4176. LastError = GetLastError();
  4177. VALIDATE(LastError)
  4178. {
  4179. ERROR_WINHTTP_CONNECTION_ERROR,
  4180. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4181. ERROR_WINHTTP_RESEND_REQUEST,
  4182. ERROR_WINHTTP_SHUTDOWN
  4183. } END_VALIDATE;
  4184. // the send failed. We don't get a notification for it
  4185. // so we must issue one. We do this by posting direct send
  4186. AsyncError = RPC_P_SEND_FAILED;
  4187. ASSERT(CurrentSendContext == QueuedSendContext);
  4188. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  4189. this
  4190. );
  4191. }
  4192. else
  4193. {
  4194. // nothing to do - notification will come asynchronously
  4195. }
  4196. }
  4197. else
  4198. {
  4199. AsyncError = RPC_P_SEND_FAILED;
  4200. ASSERT(CurrentSendContext == QueuedSendContext);
  4201. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  4202. this
  4203. );
  4204. }
  4205. }
  4206. }
  4207. // if a receive has registered itself and we're the one who finished the
  4208. // sends, do the receive
  4209. if (
  4210. (
  4211. (DelayedReceiveTrafficType == http2ttRTSWithSpecialBit)
  4212. || (DelayedReceiveTrafficType == http2ttDataWithSpecialBit)
  4213. || (DelayedReceiveTrafficType == http2ttRawWithSpecialBit)
  4214. )
  4215. &&
  4216. (LocalSendsPending == 0)
  4217. )
  4218. {
  4219. if (DelayedReceiveTrafficType == http2ttRTSWithSpecialBit)
  4220. DelayedReceiveTrafficType = http2ttRTS;
  4221. else if (DelayedReceiveTrafficType == http2ttRawWithSpecialBit)
  4222. DelayedReceiveTrafficType = http2ttRaw;
  4223. else
  4224. {
  4225. ASSERT(DelayedReceiveTrafficType == http2ttDataWithSpecialBit);
  4226. DelayedReceiveTrafficType = http2ttData;
  4227. }
  4228. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4229. if (RpcStatus == RPC_S_OK)
  4230. {
  4231. RpcStatus = Receive(DelayedReceiveTrafficType);
  4232. TopChannel->FinishSubmitAsync();
  4233. }
  4234. if (RpcStatus != RPC_S_OK)
  4235. {
  4236. // offload the result as direct receive. We use the refcount of the receive
  4237. // to complete the operation on the worker thread.
  4238. AsyncError = RpcStatus;
  4239. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  4240. this
  4241. );
  4242. }
  4243. else
  4244. {
  4245. // when it completes, it will issue its own notification
  4246. }
  4247. }
  4248. // don't call AsyncCompleteHelper here. We will always be called from DirectSendComplete
  4249. // which will call AsyncCompleteHelper for us
  4250. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4251. EventStatus);
  4252. return EventStatus;
  4253. }
  4254. void HTTP2WinHttpTransportChannel::Abort (
  4255. IN RPC_STATUS RpcStatus
  4256. )
  4257. /*++
  4258. Routine Description:
  4259. Abort the channel
  4260. Arguments:
  4261. RpcStatus - the error code with which we abort
  4262. Return Value:
  4263. Notes:
  4264. This method must be idempotent. It may be called multiple times.
  4265. --*/
  4266. {
  4267. BOOL HttpResult;
  4268. HTTP2SendContext *QueuedSendContext;
  4269. LIST_ENTRY *QueuedListEntry;
  4270. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_WINHTTP_CHANNEL, RpcStatus);
  4271. if (hRequest)
  4272. {
  4273. HttpResult = WinHttpCloseHandleImp(hRequest);
  4274. ASSERT(HttpResult);
  4275. hRequest = NULL;
  4276. }
  4277. if (hConnect)
  4278. {
  4279. HttpResult = WinHttpCloseHandleImp(hConnect);
  4280. ASSERT(HttpResult);
  4281. hConnect = NULL;
  4282. }
  4283. if (hSession)
  4284. {
  4285. HttpResult = WinHttpCloseHandleImp(hSession);
  4286. ASSERT(HttpResult);
  4287. hSession = NULL;
  4288. }
  4289. Mutex.Request();
  4290. // If there are more then 1 pending sends, then some sends must have been queued.
  4291. // We will abort the queued sends.
  4292. for (; SendsPending > 1; )
  4293. {
  4294. ASSERT(!RpcpIsListEmpty(&BufferQueueHead));
  4295. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  4296. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  4297. -- SendsPending;
  4298. ASSERT(SendsPending > 0);
  4299. HTTP2TransportChannel::SendComplete(RpcStatus, QueuedSendContext);
  4300. AsyncCompleteHelper(RpcStatus);
  4301. }
  4302. Mutex.Clear();
  4303. }
  4304. void HTTP2WinHttpTransportChannel::FreeObject (
  4305. void
  4306. )
  4307. /*++
  4308. Routine Description:
  4309. Frees the object. Acts like a destructor for the
  4310. channel.
  4311. Arguments:
  4312. Return Value:
  4313. --*/
  4314. {
  4315. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_WINHTTP_CHANNEL, 0);
  4316. if (pReadBuffer)
  4317. {
  4318. RpcFreeBuffer(pReadBuffer);
  4319. pReadBuffer = NULL;
  4320. }
  4321. HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  4322. }
  4323. RPC_STATUS HTTP2WinHttpTransportChannel::DirectReceiveComplete (
  4324. OUT BYTE **ReceivedBuffer,
  4325. OUT ULONG *ReceivedBufferLength,
  4326. OUT void **RuntimeConnection
  4327. )
  4328. /*++
  4329. Routine Description:
  4330. Direct receive completion (i.e. we posted a receive
  4331. to ourselves)
  4332. Arguments:
  4333. ReceivedBuffer - the buffer that we received.
  4334. ReceivedBufferLength - the length of the received
  4335. buffer
  4336. RuntimeConnection - the connection to return to the runtime
  4337. if the packet is not consumed.
  4338. Return Value:
  4339. RPC_S_OK, RPC_P_PACKET_CONSUMED or RPC_S_* errors.
  4340. --*/
  4341. {
  4342. RPC_STATUS RpcStatus;
  4343. BOOL HttpResult;
  4344. ULONG WaitResult;
  4345. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4346. AsyncError);
  4347. *RuntimeConnection = TopChannel->GetRuntimeConnection();
  4348. // two cases - previous coalesced read and a real read
  4349. if (iLastRead && iLastRead == MaxReadBuffer)
  4350. {
  4351. // previous coalesced read
  4352. *ReceivedBufferLength = MaxReadBuffer;
  4353. iLastRead = 0;
  4354. RpcStatus = RPC_S_OK;
  4355. }
  4356. else
  4357. {
  4358. // real read
  4359. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  4360. if ((AsyncError == RPC_S_OK)
  4361. && (NumberOfBytesTransferred == 0))
  4362. {
  4363. // zero bytes transferred indicates end of request.
  4364. AsyncError = RPC_P_RECEIVE_FAILED;
  4365. }
  4366. RpcStatus = AsyncError;
  4367. AsyncError = RPC_S_INTERNAL_ERROR;
  4368. if (RpcStatus == RPC_S_OK)
  4369. {
  4370. if (pReadBuffer == NULL)
  4371. {
  4372. if (NumberOfBytesTransferred > iPostSize)
  4373. MaxReadBuffer = NumberOfBytesTransferred;
  4374. else
  4375. MaxReadBuffer = iPostSize;
  4376. pReadBuffer = (BYTE *)RpcAllocateBuffer(MaxReadBuffer);
  4377. // fall through for error check below
  4378. }
  4379. else if (MaxReadBuffer - iLastRead < NumberOfBytesTransferred)
  4380. {
  4381. ASSERT(iLastRead < MaxReadBuffer);
  4382. // Buffer too small for the message.
  4383. RpcStatus = TransConnectionReallocPacket(NULL,
  4384. &pReadBuffer,
  4385. iLastRead,
  4386. iLastRead + NumberOfBytesTransferred
  4387. );
  4388. if (RpcStatus != RPC_S_OK)
  4389. {
  4390. RpcFreeBuffer(pReadBuffer);
  4391. pReadBuffer = NULL;
  4392. }
  4393. MaxReadBuffer = iLastRead + NumberOfBytesTransferred;
  4394. }
  4395. else
  4396. {
  4397. // buffer should be enough - no need to reallocate
  4398. ASSERT(iLastRead < MaxReadBuffer);
  4399. }
  4400. if (pReadBuffer == NULL)
  4401. {
  4402. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4403. NumberOfBytesTransferred = 0;
  4404. }
  4405. else
  4406. {
  4407. // we need to temporarily get into submission context to synchronize
  4408. // with Aborts
  4409. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4410. if (RpcStatus == RPC_S_OK)
  4411. {
  4412. ASSERT(SyncEvent == NULL);
  4413. SyncEvent = I_RpcTransGetThreadEvent();
  4414. ResetEvent(SyncEvent);
  4415. HttpResult = WinHttpReadDataImp(hRequest,
  4416. pReadBuffer + iLastRead,
  4417. NumberOfBytesTransferred,
  4418. &NumberOfBytesTransferred
  4419. );
  4420. // wait for read complete to finish
  4421. WaitResult = WaitForSingleObject(SyncEvent, INFINITE);
  4422. // this cannot fail
  4423. ASSERT(WaitResult == WAIT_OBJECT_0);
  4424. SyncEvent = NULL;
  4425. // the data are available. We cannot possibly fail
  4426. ASSERT(HttpResult);
  4427. TopChannel->FinishSubmitAsync();
  4428. }
  4429. else
  4430. {
  4431. // fall through with the error.
  4432. }
  4433. }
  4434. }
  4435. *ReceivedBufferLength = NumberOfBytesTransferred;
  4436. }
  4437. RpcStatus = HTTP2WinHttpTransportChannel::ReceiveComplete(RpcStatus,
  4438. http2ttRaw,
  4439. ReceivedBuffer,
  4440. (UINT *)ReceivedBufferLength
  4441. );
  4442. // did we receive an incomplete buffer?
  4443. if ((RpcStatus == RPC_S_OK) && (*ReceivedBuffer == NULL))
  4444. {
  4445. // hide it from the runtime
  4446. RpcStatus = RPC_P_PACKET_CONSUMED;
  4447. }
  4448. // AsyncCompleteHelper has already been called in ReceiveComplete
  4449. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4450. RpcStatus);
  4451. return RpcStatus;
  4452. }
  4453. RPC_STATUS HTTP2WinHttpTransportChannel::DirectSendComplete (
  4454. OUT BYTE **SentBuffer,
  4455. OUT void **SendContext
  4456. )
  4457. /*++
  4458. Routine Description:
  4459. Direct send complete notification. Complete the send
  4460. passing it only through channels that have seen it (i.e.
  4461. above us).
  4462. Arguments:
  4463. SentBuffer - on output the buffer that we tried to send
  4464. SendContext - on output contains the send context as
  4465. seen by the runtime
  4466. Return Value:
  4467. RPC_S_OK to return error to runtime
  4468. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  4469. RPC_S_* error - return error to runtime
  4470. --*/
  4471. {
  4472. HTTP2SendContext *LocalCurrentSendContext;
  4473. RPC_STATUS RpcStatus;
  4474. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4475. AsyncError);
  4476. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  4477. ASSERT(CurrentSendContext);
  4478. State = whtcsSentRequest;
  4479. LocalCurrentSendContext = CurrentSendContext;
  4480. // CurrentSendContext is zeroed out by the call.
  4481. RpcStatus = HTTP2WinHttpTransportChannel::SendComplete(AsyncError, LocalCurrentSendContext);
  4482. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  4483. {
  4484. // this will return to the runtime. Make sure it is valid
  4485. I_RpcTransVerifyClientRuntimeCallFromContext(LocalCurrentSendContext);
  4486. *SendContext = LocalCurrentSendContext;
  4487. *SentBuffer = LocalCurrentSendContext->pWriteBuffer;
  4488. }
  4489. else
  4490. {
  4491. // the packet was a transport packet - it won't be seen by the runtime
  4492. *SendContext = NULL;
  4493. *SentBuffer = NULL;
  4494. }
  4495. RpcStatus = AsyncCompleteHelper(RpcStatus);
  4496. // do not touch this pointer after here unless the list was not-empty
  4497. // (which implies we still have refcounts)
  4498. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4499. RpcStatus);
  4500. return RpcStatus;
  4501. }
  4502. void HTTP2WinHttpTransportChannel::DelayedReceive (
  4503. void
  4504. )
  4505. /*++
  4506. Routine Description:
  4507. Performs a delayed receive. The first receive on an WinHttp
  4508. channel is delayed because we must receive the headers before
  4509. we can do the actual receive.
  4510. Arguments:
  4511. Return Value:
  4512. Note: Will be called from upcall context
  4513. --*/
  4514. {
  4515. BOOL HttpResult;
  4516. ULONG LastError;
  4517. RPC_STATUS RpcStatus;
  4518. BOOL InSubmissionContext;
  4519. BYTE *Ignored;
  4520. UINT BufferLength;
  4521. ULONG StatusCode;
  4522. ULONG StatusCodeLength;
  4523. ULONG HttpStatus;
  4524. RPC_CHAR ConnectionOptions[40];
  4525. RPC_CHAR *ConnectionOptionsToUse;
  4526. ULONG ConnectionOptionsLength;
  4527. int i;
  4528. RPC_CHAR *KeepAliveString;
  4529. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DELAYED_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4530. AsyncError);
  4531. // Check if we have received an async failure.
  4532. LastError = AsyncError;
  4533. AsyncError = RPC_S_INTERNAL_ERROR;
  4534. RpcStatus = RPC_S_OK;
  4535. InSubmissionContext = FALSE;
  4536. if (LastError == RPC_S_OK)
  4537. {
  4538. // get into submission context
  4539. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4540. if (RpcStatus == RPC_S_OK)
  4541. {
  4542. InSubmissionContext = TRUE;
  4543. StatusCodeLength = sizeof(StatusCode);
  4544. HttpResult = WinHttpQueryHeadersImp (
  4545. hRequest,
  4546. WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
  4547. WINHTTP_HEADER_NAME_BY_INDEX,
  4548. &StatusCode,
  4549. &StatusCodeLength,
  4550. WINHTTP_NO_HEADER_INDEX
  4551. );
  4552. if (!HttpResult)
  4553. {
  4554. LastError = GetLastError();
  4555. }
  4556. else
  4557. {
  4558. if (StatusCode != HTTP_STATUS_OK)
  4559. {
  4560. if ((StatusCode >= RPC_S_INVALID_STRING_BINDING) && (StatusCode <= RPC_X_BAD_STUB_DATA))
  4561. {
  4562. // if it is an RPC error code, just return it.
  4563. RpcStatus = StatusCode;
  4564. }
  4565. else if ((StatusCode == HTTP_STATUS_NOT_FOUND)
  4566. || (StatusCode == HTTP_STATUS_BAD_METHOD)
  4567. || (StatusCode == HTTP_STATUS_BAD_METHOD)
  4568. || (StatusCode == HTTP_STATUS_SERVER_ERROR)
  4569. || (StatusCode == HTTP_STATUS_NOT_SUPPORTED)
  4570. || (StatusCode == HTTP_STATUS_SERVICE_UNAVAIL) )
  4571. {
  4572. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  4573. }
  4574. else if (StatusCode == HTTP_STATUS_REQUEST_TOO_LARGE)
  4575. RpcStatus = RPC_S_SERVER_OUT_OF_MEMORY;
  4576. else if (StatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
  4577. {
  4578. if ((HttpCredentials == NULL)
  4579. || (HttpCredentials->AuthenticationTarget & RPC_C_HTTP_AUTHN_TARGET_PROXY) == 0)
  4580. {
  4581. // we were not asked to authenticate against a proxy. Just fail
  4582. RpcStatus = RPC_S_ACCESS_DENIED;
  4583. }
  4584. else
  4585. {
  4586. ChosenAuthScheme = NegotiateAuthScheme();
  4587. if (ChosenAuthScheme == 0)
  4588. RpcStatus = RPC_S_ACCESS_DENIED;
  4589. else
  4590. {
  4591. State = whtcsDraining;
  4592. HttpResult = WinHttpQueryDataAvailableImp(hRequest,
  4593. &NumberOfBytesTransferred
  4594. );
  4595. ASSERT(HttpResult);
  4596. RpcStatus = RPC_S_OK;
  4597. goto CleanupAndExit;
  4598. }
  4599. }
  4600. }
  4601. else if (StatusCode == HTTP_STATUS_DENIED)
  4602. {
  4603. if ((HttpCredentials == NULL)
  4604. || (HttpCredentials->AuthenticationTarget & RPC_C_HTTP_AUTHN_TARGET_SERVER) == 0)
  4605. {
  4606. // we were not asked to authenticate against a server. Just fail
  4607. RpcStatus = RPC_S_ACCESS_DENIED;
  4608. }
  4609. else
  4610. {
  4611. ChosenAuthScheme = NegotiateAuthScheme();
  4612. if (ChosenAuthScheme == 0)
  4613. RpcStatus = RPC_S_ACCESS_DENIED;
  4614. else
  4615. {
  4616. State = whtcsDraining;
  4617. HttpResult = WinHttpQueryDataAvailableImp(hRequest,
  4618. &NumberOfBytesTransferred
  4619. );
  4620. ASSERT(HttpResult);
  4621. RpcStatus = RPC_S_OK;
  4622. goto CleanupAndExit;
  4623. }
  4624. }
  4625. }
  4626. else
  4627. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4628. }
  4629. else
  4630. {
  4631. // RpcStatus is already set above
  4632. ASSERT(RpcStatus == RPC_S_OK);
  4633. ConnectionOptionsLength = sizeof(ConnectionOptions);
  4634. ConnectionOptionsToUse = ConnectionOptions;
  4635. for (i = 0; i < 2; i ++)
  4636. {
  4637. HttpResult = WinHttpQueryHeadersImp (
  4638. hRequest,
  4639. WINHTTP_QUERY_CONNECTION,
  4640. WINHTTP_HEADER_NAME_BY_INDEX,
  4641. ConnectionOptionsToUse,
  4642. &ConnectionOptionsLength,
  4643. WINHTTP_NO_HEADER_INDEX
  4644. );
  4645. if (!HttpResult)
  4646. {
  4647. LastError = GetLastError();
  4648. if (LastError == ERROR_INSUFFICIENT_BUFFER)
  4649. {
  4650. ConnectionOptionsToUse = new RPC_CHAR[ConnectionOptionsLength];
  4651. if (ConnectionOptionsToUse == NULL)
  4652. {
  4653. LastError = RPC_S_OUT_OF_MEMORY;
  4654. // fall through with the error below
  4655. break;
  4656. }
  4657. }
  4658. else if (LastError == ERROR_WINHTTP_HEADER_NOT_FOUND)
  4659. {
  4660. // we did not get keep alives. This is ok
  4661. LastError = RPC_S_OK;
  4662. KeepAlive = FALSE;
  4663. break;
  4664. }
  4665. else
  4666. {
  4667. LastError = RPC_S_OUT_OF_MEMORY;
  4668. // fall through with the error below
  4669. break;
  4670. }
  4671. }
  4672. else
  4673. {
  4674. LastError = RPC_S_OK;
  4675. break;
  4676. }
  4677. } // for (i ...
  4678. ASSERT(LastError != ERROR_INSUFFICIENT_BUFFER);
  4679. if (LastError == RPC_S_OK)
  4680. {
  4681. // we got the connection options. Do we have keep alive?
  4682. KeepAliveString = RpcpStrStr(ConnectionOptionsToUse, L"Keep-Alive");
  4683. if (KeepAliveString)
  4684. KeepAlive = TRUE;
  4685. }
  4686. if (ConnectionOptionsToUse != ConnectionOptions)
  4687. delete [] ConnectionOptionsToUse;
  4688. } // StatusCode == HTTP_STATUS_OK
  4689. } // WinHttpQueryHeadersImp succeeded
  4690. } // BeginSimpleSubmitAsync succeeded
  4691. else
  4692. {
  4693. // BeginSimpleSubmitAsync failed - fall through with the error
  4694. // RpcStatus and success LastError
  4695. ASSERT(LastError == RPC_S_OK);
  4696. }
  4697. }
  4698. if (LastError != RPC_S_OK)
  4699. {
  4700. VALIDATE(LastError)
  4701. {
  4702. ERROR_WINHTTP_CANNOT_CONNECT,
  4703. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  4704. ERROR_WINHTTP_CONNECTION_ERROR,
  4705. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4706. ERROR_WINHTTP_INVALID_URL,
  4707. ERROR_WINHTTP_LOGIN_FAILURE,
  4708. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  4709. ERROR_WINHTTP_OUT_OF_HANDLES,
  4710. ERROR_WINHTTP_REDIRECT_FAILED,
  4711. ERROR_WINHTTP_RESEND_REQUEST,
  4712. ERROR_WINHTTP_SECURE_FAILURE,
  4713. ERROR_WINHTTP_SHUTDOWN,
  4714. ERROR_WINHTTP_TIMEOUT,
  4715. ERROR_NOT_SUPPORTED,
  4716. RPC_P_SEND_FAILED,
  4717. RPC_P_RECEIVE_FAILED,
  4718. RPC_P_AUTH_NEEDED
  4719. } END_VALIDATE;
  4720. switch (LastError)
  4721. {
  4722. case ERROR_WINHTTP_CONNECTION_ERROR:
  4723. case ERROR_WINHTTP_REDIRECT_FAILED:
  4724. case ERROR_WINHTTP_RESEND_REQUEST:
  4725. case ERROR_WINHTTP_SHUTDOWN:
  4726. case ERROR_WINHTTP_CANNOT_CONNECT:
  4727. case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
  4728. case ERROR_WINHTTP_INVALID_URL:
  4729. case ERROR_WINHTTP_LOGIN_FAILURE:
  4730. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  4731. case ERROR_WINHTTP_SECURE_FAILURE:
  4732. case RPC_P_AUTH_NEEDED:
  4733. RpcStatus = RPC_P_RECEIVE_FAILED;
  4734. break;
  4735. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  4736. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4737. break;
  4738. case ERROR_NOT_SUPPORTED:
  4739. RpcStatus = RPC_S_CANNOT_SUPPORT;
  4740. break;
  4741. case ERROR_WINHTTP_TIMEOUT:
  4742. RpcStatus = RPC_S_CALL_CANCELLED;
  4743. break;
  4744. case RPC_P_SEND_FAILED:
  4745. case RPC_P_RECEIVE_FAILED:
  4746. RpcStatus = LastError;
  4747. break;
  4748. default:
  4749. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4750. break;
  4751. }
  4752. VALIDATE(RpcStatus)
  4753. {
  4754. RPC_S_OUT_OF_MEMORY,
  4755. RPC_S_OUT_OF_RESOURCES,
  4756. RPC_P_RECEIVE_FAILED,
  4757. RPC_S_CALL_CANCELLED,
  4758. RPC_P_SEND_FAILED,
  4759. RPC_P_CONNECTION_SHUTDOWN,
  4760. RPC_P_TIMEOUT
  4761. } END_VALIDATE;
  4762. }
  4763. if (RpcStatus == RPC_S_OK)
  4764. {
  4765. ASSERT(InSubmissionContext);
  4766. RpcStatus = HTTP2FragmentReceiver::Receive(DelayedReceiveTrafficType);
  4767. }
  4768. CleanupAndExit:
  4769. if (InSubmissionContext)
  4770. {
  4771. TopChannel->FinishSubmitAsync();
  4772. }
  4773. DelayedReceiveTrafficType = http2ttNone;
  4774. if (RpcStatus != RPC_S_OK)
  4775. {
  4776. // we got a failure. Issue receive complete. Since DelayedReceive
  4777. // happens only on channel recycling, and then we know we
  4778. // issue RTS receive, we don't need to indicate this to the runtime
  4779. BufferLength = 0;
  4780. RpcStatus = ReceiveComplete(RpcStatus,
  4781. DelayedReceiveTrafficType,
  4782. &Ignored,
  4783. &BufferLength
  4784. );
  4785. ASSERT(RpcStatus == RPC_P_PACKET_CONSUMED);
  4786. }
  4787. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DELAYED_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4788. RpcStatus);
  4789. }
  4790. void HTTP2WinHttpTransportChannel::VerifyServerCredentials (
  4791. void
  4792. )
  4793. /*++
  4794. Routine Description:
  4795. Verifies that the server credentials match the subject info we
  4796. were given.
  4797. Arguments:
  4798. Return Value:
  4799. --*/
  4800. {
  4801. BOOL HttpResult;
  4802. PCERT_CONTEXT CertContext;
  4803. ULONG OptionSize;
  4804. RPC_STATUS RpcStatus;
  4805. RPC_CHAR *StringSPN;
  4806. RPC_STATUS AbortError;
  4807. // make sure nobody has touched the async error after open
  4808. ASSERT((AsyncError == RPC_S_OK)
  4809. || ((AsyncError == RPC_S_INTERNAL_ERROR)));
  4810. // if no credentials, nothing to verify
  4811. if ((HttpCredentials == NULL)
  4812. || (HttpCredentials->ServerCertificateSubject == NULL))
  4813. return;
  4814. OptionSize = sizeof(PCERT_CONTEXT);
  4815. HttpResult = WinHttpQueryOptionImp(hRequest,
  4816. WINHTTP_OPTION_SERVER_CERT_CONTEXT,
  4817. &CertContext,
  4818. &OptionSize
  4819. );
  4820. if (!HttpResult)
  4821. {
  4822. AsyncError = GetLastError();
  4823. VALIDATE(AsyncError)
  4824. {
  4825. ERROR_NOT_ENOUGH_MEMORY,
  4826. ERROR_INVALID_OPERATION
  4827. } END_VALIDATE;
  4828. switch (AsyncError)
  4829. {
  4830. case ERROR_INVALID_OPERATION:
  4831. // we will get this when we ask for the certificate of non
  4832. // SSL connection
  4833. AsyncError = RPC_S_ACCESS_DENIED;
  4834. break;
  4835. default:
  4836. AbortError = RPC_S_OUT_OF_MEMORY;
  4837. }
  4838. goto AbortAndExit;
  4839. }
  4840. RpcStatus = I_RpcTransCertMatchPrincipalName(CertContext, HttpCredentials->ServerCertificateSubject);
  4841. if (RpcStatus != RPC_S_OK)
  4842. {
  4843. AbortError = AsyncError = RpcStatus;
  4844. goto AbortAndExit;
  4845. }
  4846. return;
  4847. AbortAndExit:
  4848. ASSERT(AsyncError != ERROR_SUCCESS);
  4849. // HTTP2WinHttpTransportChannel::Abort is idempotent. We'll call it now to
  4850. // tell WinHttp to abort, and ClientOpen will call it again. This is ok.
  4851. Abort(AbortError);
  4852. }
  4853. RPC_STATUS HTTP2WinHttpTransportChannel::PostReceive (
  4854. void
  4855. )
  4856. /*++
  4857. Routine Description:
  4858. Posts a receive to WinHttp.
  4859. Arguments:
  4860. Return Value:
  4861. RPC_S_OK or RPC_S_* error
  4862. Note: May be called from both submission and upcall context
  4863. --*/
  4864. {
  4865. BOOL HttpResult;
  4866. RPC_STATUS RpcStatus;
  4867. ULONG LastError;
  4868. ULONG AvailableLength;
  4869. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL, 0);
  4870. ASSERT(State == whtcsReceivedResponse);
  4871. State = whtcsReading;
  4872. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4873. if (RpcStatus != RPC_S_OK)
  4874. return RpcStatus;
  4875. HttpResult = WinHttpQueryDataAvailableImp (hRequest,
  4876. &NumberOfBytesTransferred
  4877. );
  4878. TopChannel->FinishSubmitAsync();
  4879. if (!HttpResult)
  4880. {
  4881. LastError = GetLastError();
  4882. VALIDATE(LastError)
  4883. {
  4884. ERROR_NOT_ENOUGH_MEMORY,
  4885. ERROR_WINHTTP_CONNECTION_ERROR,
  4886. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4887. ERROR_WINHTTP_RESEND_REQUEST,
  4888. ERROR_WINHTTP_SHUTDOWN
  4889. } END_VALIDATE;
  4890. RpcStatus = RPC_P_RECEIVE_FAILED;
  4891. }
  4892. else
  4893. {
  4894. // If the function returned non-zero,
  4895. // then it will complete asyncronously.
  4896. // Nothing to do here, we will receive async notification.
  4897. RpcStatus = RPC_S_OK;
  4898. }
  4899. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL, RpcStatus);
  4900. return RpcStatus;
  4901. }
  4902. ULONG HTTP2WinHttpTransportChannel::GetPostRuntimeEvent (
  4903. void
  4904. )
  4905. /*++
  4906. Routine Description:
  4907. Gets the message to be posted to the runtime.
  4908. Arguments:
  4909. Return Value:
  4910. The message to post to the runtime
  4911. --*/
  4912. {
  4913. return HTTP2_WINHTTP_DIRECT_RECV;
  4914. }
  4915. ULONG HTTP2WinHttpTransportChannel::NegotiateAuthScheme (
  4916. void
  4917. )
  4918. /*++
  4919. Routine Description:
  4920. Negotiates an auth scheme supported by client and server/proxy
  4921. according to preference rules.
  4922. Arguments:
  4923. Return Value:
  4924. The negotiated scheme or 0 if no scheme could be negotiated.
  4925. Notes:
  4926. The actual server/proxy supported/preferred schemes will be retrieved
  4927. from hRequest.
  4928. --*/
  4929. {
  4930. BOOL HttpResult;
  4931. ULONG Ignored;
  4932. ULONG ServerSupportedSchemes; // we use Server for brevity, but this
  4933. ULONG ServerPreferredScheme; // applies to proxies as well
  4934. ULONG *ClientSupportedSchemes;
  4935. ULONG CountOfClientSupportedSchemes;
  4936. int i;
  4937. HttpResult = WinHttpQueryAuthSchemesImp (hRequest,
  4938. &ServerSupportedSchemes,
  4939. &ServerPreferredScheme,
  4940. &Ignored // pdwAuthTarget - we have already determined this
  4941. // from the error code - ignore now.
  4942. );
  4943. if (!HttpResult)
  4944. return 0;
  4945. // first, if we support the server preference, we just choose
  4946. // that.
  4947. CountOfClientSupportedSchemes = HttpCredentials->NumberOfAuthnSchemes;
  4948. ClientSupportedSchemes = HttpCredentials->AuthnSchemes;
  4949. ASSERT(CountOfClientSupportedSchemes > 0);
  4950. ASSERT(ClientSupportedSchemes != NULL);
  4951. for (i = 0; i < CountOfClientSupportedSchemes; i ++)
  4952. {
  4953. if (ServerPreferredScheme == ClientSupportedSchemes[i])
  4954. return ServerPreferredScheme;
  4955. }
  4956. // client doesn't support what the server asks for. Try whether the server
  4957. // supports what the client prefers
  4958. for (i = 0; i < CountOfClientSupportedSchemes; i ++)
  4959. {
  4960. if (ServerSupportedSchemes & ClientSupportedSchemes[i])
  4961. return ClientSupportedSchemes[i];
  4962. }
  4963. return 0;
  4964. }
  4965. void HTTP2WinHttpTransportChannel::ContinueDrainChannel (
  4966. void
  4967. )
  4968. /*++
  4969. Routine Description:
  4970. Continue draining the channel after authentication challenge. We
  4971. need to drain the channel before we can proceed with the next
  4972. request. The number of bytes received is in NumberOfBytesTransferred.
  4973. If the channel was aborted in the meantime, issue receive
  4974. complete.
  4975. Arguments:
  4976. Return Value:
  4977. --*/
  4978. {
  4979. BYTE *Buffer;
  4980. RPC_STATUS RpcStatus;
  4981. BOOL HttpResult;
  4982. // read the reported bytes. Then query again. If the
  4983. // number of bytes reported is 0, issue a receive
  4984. // for RPC_P_AUTH_NEEDED
  4985. if (NumberOfBytesTransferred > 0)
  4986. {
  4987. Buffer = (BYTE *)RpcAllocateBuffer(NumberOfBytesTransferred);
  4988. if (Buffer == NULL)
  4989. {
  4990. AsyncError = RPC_S_OUT_OF_MEMORY;
  4991. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  4992. this
  4993. );
  4994. return;
  4995. }
  4996. // get into submissions context in order to safely access the
  4997. // request
  4998. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4999. if (RpcStatus != RPC_S_OK)
  5000. {
  5001. RpcFreeBuffer(Buffer);
  5002. AsyncError = RpcStatus;
  5003. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5004. this
  5005. );
  5006. return;
  5007. }
  5008. HttpResult = WinHttpReadDataImp (hRequest,
  5009. Buffer,
  5010. NumberOfBytesTransferred,
  5011. &NumberOfBytesTransferred
  5012. );
  5013. // the data are here. This cannot fail
  5014. ASSERT(HttpResult);
  5015. RpcFreeBuffer(Buffer);
  5016. // ask for more
  5017. HttpResult = WinHttpQueryDataAvailableImp (hRequest,
  5018. &NumberOfBytesTransferred
  5019. );
  5020. ASSERT(HttpResult);
  5021. TopChannel->FinishSubmitAsync();
  5022. }
  5023. else
  5024. {
  5025. AsyncError = RPC_P_AUTH_NEEDED;
  5026. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5027. this
  5028. );
  5029. }
  5030. }
  5031. /*********************************************************************
  5032. HTTP2ProxySocketTransportChannel
  5033. *********************************************************************/
  5034. RPC_STATUS HTTP2ProxySocketTransportChannel::AsyncCompleteHelper (
  5035. IN RPC_STATUS CurrentStatus
  5036. )
  5037. /*++
  5038. Routine Description:
  5039. Helper routine that helps complete an async operation
  5040. Arguments:
  5041. CurrentStatus - the current status of the operation
  5042. Return Value:
  5043. The status to return to the runtime.
  5044. --*/
  5045. {
  5046. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_COMPLETE_HELPER, HTTP2LOG_OT_PROXY_SOCKET_CHANNEL, CurrentStatus);
  5047. ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  5048. return RPC_P_PACKET_CONSUMED;
  5049. }
  5050. /*********************************************************************
  5051. HTTP2IISTransportChannel
  5052. *********************************************************************/
  5053. const char ServerErrorString[] = "HTTP/1.0 503 RPC Error: %X\r\n\r\n";
  5054. DWORD
  5055. ReplyToClientWithStatus (
  5056. IN EXTENSION_CONTROL_BLOCK *pECB,
  5057. IN RPC_STATUS RpcStatus
  5058. )
  5059. /*++
  5060. Routine Description:
  5061. Sends a reply to the client with the given error code as error.
  5062. Arguments:
  5063. pECB - extension control block
  5064. RpcStatus - error code to be returned to client
  5065. Return Value:
  5066. Return value appropriate for return to IIS (i.e. HSE_STATUS_*)
  5067. --*/
  5068. {
  5069. // size is the error string + 10 space for the error code
  5070. char Buffer[sizeof(ServerErrorString) + 10];
  5071. ULONG Size;
  5072. ULONG Status;
  5073. BOOL Result;
  5074. DWORD dwFlags = (HSE_IO_SYNC | HSE_IO_NODELAY);
  5075. sprintf (Buffer,
  5076. ServerErrorString,
  5077. RpcStatus
  5078. );
  5079. Size = RpcpStringLengthA(Buffer);
  5080. if (!pECB->WriteClient(pECB->ConnID, Buffer, &Size, dwFlags))
  5081. {
  5082. Status = GetLastError();
  5083. #ifdef DBG_ERROR
  5084. DbgPrint("ReplyToClientWithStatus(): failed: %d\n", Status);
  5085. #endif
  5086. return RPC_S_OUT_OF_MEMORY;
  5087. }
  5088. else
  5089. return RPC_S_OK;
  5090. }
  5091. RPC_STATUS HTTP2IISTransportChannel::ReceiveComplete (
  5092. IN RPC_STATUS EventStatus,
  5093. IN HTTP2TrafficType TrafficType,
  5094. IN BYTE *Buffer,
  5095. IN UINT BufferLength
  5096. )
  5097. /*++
  5098. Routine Description:
  5099. Receive complete notification.
  5100. Arguments:
  5101. EventStatus - status of the operation
  5102. TrafficType - the type of traffic we have received
  5103. Buffer - the received buffer (success only)
  5104. BufferLength - the length of the received buffer (success only)
  5105. Return Value:
  5106. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5107. --*/
  5108. {
  5109. // make sure nobody gets here. Everybody should be using the internal
  5110. // version
  5111. ASSERT(0);
  5112. return RPC_S_INTERNAL_ERROR;
  5113. }
  5114. void HTTP2IISTransportChannel::Abort (
  5115. IN RPC_STATUS RpcStatus
  5116. )
  5117. /*++
  5118. Routine Description:
  5119. Abort the channel
  5120. Arguments:
  5121. RpcStatus - the error code with which we abort
  5122. Return Value:
  5123. --*/
  5124. {
  5125. BOOL Result;
  5126. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_IIS_CHANNEL, RpcStatus);
  5127. ReplyToClientWithStatus(ControlBlock, RpcStatus);
  5128. // must abort the IIS session
  5129. Result = ControlBlock->ServerSupportFunction( ControlBlock->ConnID,
  5130. HSE_REQ_CLOSE_CONNECTION,
  5131. NULL,
  5132. NULL,
  5133. NULL);
  5134. ASSERT(Result);
  5135. }
  5136. void HTTP2IISTransportChannel::FreeObject (
  5137. void
  5138. )
  5139. /*++
  5140. Routine Description:
  5141. Frees the object. Acts like a destructor for the
  5142. channel.
  5143. Arguments:
  5144. Return Value:
  5145. --*/
  5146. {
  5147. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5148. FreeIISControlBlock();
  5149. if (pReadBuffer)
  5150. {
  5151. RpcFreeBuffer(pReadBuffer);
  5152. pReadBuffer = NULL;
  5153. }
  5154. HTTP2IISTransportChannel::~HTTP2IISTransportChannel();
  5155. }
  5156. void HTTP2IISTransportChannel::IOCompleted (
  5157. IN ULONG Bytes,
  5158. DWORD Error
  5159. )
  5160. /*++
  5161. Routine Description:
  5162. An IO completed. Figure out what IO and what to do with it.
  5163. Arguments:
  5164. Return Value:
  5165. --*/
  5166. {
  5167. RPC_STATUS RpcStatus;
  5168. BYTE *Ignored;
  5169. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_IIS_IO_COMPLETED, HTTP2LOG_OT_IIS_CHANNEL, Error);
  5170. if (Direction == iistcdReceive)
  5171. {
  5172. (void) ReceiveCompleteInternal(Error ? RPC_P_RECEIVE_FAILED : RPC_S_OK,
  5173. http2ttRaw,
  5174. TRUE, // ReadCompleted
  5175. &Ignored,
  5176. (UINT *)&Bytes
  5177. );
  5178. }
  5179. else
  5180. {
  5181. if (Error == ERROR_SUCCESS)
  5182. {
  5183. ASSERT(Bytes == CurrentSendContext->maxWriteBuffer);
  5184. }
  5185. (void) SendComplete(Error ? RPC_P_SEND_FAILED : RPC_S_OK, CurrentSendContext);
  5186. }
  5187. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_IIS_IO_COMPLETED, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5188. }
  5189. void HTTP2IISTransportChannel::DirectReceive (
  5190. void
  5191. )
  5192. /*++
  5193. Routine Description:
  5194. Direct receive callback from the thread pool
  5195. Arguments:
  5196. Return Value:
  5197. --*/
  5198. {
  5199. ULONG Bytes;
  5200. RPC_STATUS RpcStatus;
  5201. BYTE *Ignored;
  5202. Bytes = iLastRead;
  5203. iLastRead = 0;
  5204. RpcStatus = ReceiveCompleteInternal(RPC_S_OK,
  5205. http2ttRaw,
  5206. FALSE, // ReadCompleted
  5207. &Ignored,
  5208. (UINT *)&Bytes
  5209. );
  5210. ASSERT(RpcStatus != RPC_S_INTERNAL_ERROR);
  5211. ASSERT(RpcStatus != RPC_P_PARTIAL_RECEIVE);
  5212. }
  5213. RPC_STATUS HTTP2IISTransportChannel::ReceiveCompleteInternal (
  5214. IN RPC_STATUS EventStatus,
  5215. IN HTTP2TrafficType TrafficType,
  5216. IN BOOL ReadCompleted,
  5217. IN OUT BYTE **Buffer,
  5218. IN OUT UINT *BufferLength
  5219. )
  5220. /*++
  5221. Routine Description:
  5222. Receive complete notification for the IIS transport channel. Somewhat
  5223. different signature than normal receive complete.
  5224. Arguments:
  5225. EventStatus - status of the operation
  5226. TrafficType - the type of traffic we have received
  5227. ReadCompleted - non-zero if a read completed. FALSE if it hasn't.
  5228. Buffer - the buffer. Must be NULL at this level on input. On
  5229. output contains the buffer for the current receive. If NULL
  5230. on output, we did not have a full packet. Undefined on failure.
  5231. BufferLength - the actual number of bytes received. On output the
  5232. number of bytes for the current packet. If 0 on output,
  5233. we did not have a complete packet. Undefined on failure.
  5234. Return Value:
  5235. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5236. --*/
  5237. {
  5238. if (ReadCompleted)
  5239. ReadsPending --;
  5240. ASSERT(ReadsPending == 0);
  5241. return HTTP2FragmentReceiver::ReceiveComplete (EventStatus,
  5242. TrafficType,
  5243. Buffer,
  5244. BufferLength
  5245. );
  5246. }
  5247. void HTTP2IISTransportChannel::FreeIISControlBlock (
  5248. void
  5249. )
  5250. /*++
  5251. Routine Description:
  5252. Frees the IIS control block associated with this channel
  5253. Arguments:
  5254. Return Value:
  5255. --*/
  5256. {
  5257. BOOL Result;
  5258. Result = ControlBlock->ServerSupportFunction( ControlBlock->ConnID,
  5259. HSE_REQ_DONE_WITH_SESSION,
  5260. NULL,
  5261. NULL,
  5262. NULL);
  5263. ASSERT(Result);
  5264. ControlBlock = NULL;
  5265. }
  5266. RPC_STATUS HTTP2IISTransportChannel::AsyncCompleteHelper (
  5267. IN RPC_STATUS CurrentStatus
  5268. )
  5269. /*++
  5270. Routine Description:
  5271. A helper function that completes an async io.
  5272. Arguments:
  5273. CurrentStatus - the status with which the complete
  5274. notification completed.
  5275. Return Value:
  5276. --*/
  5277. {
  5278. return ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  5279. }
  5280. RPC_STATUS HTTP2IISTransportChannel::PostReceive (
  5281. void
  5282. )
  5283. /*++
  5284. Routine Description:
  5285. Posts a receive to IIS.
  5286. Arguments:
  5287. Return Value:
  5288. RPC_S_OK or RPC_S_* error
  5289. Note: May be called from both submission and upcall context
  5290. --*/
  5291. {
  5292. BOOL Result;
  5293. RPC_STATUS RpcStatus;
  5294. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5295. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  5296. if (RpcStatus != RPC_S_OK)
  5297. return RpcStatus;
  5298. ASSERT (Direction == iistcdReceive);
  5299. if (pReadBuffer == NULL)
  5300. {
  5301. pReadBuffer = (BYTE *)RpcAllocateBuffer(gPostSize);
  5302. if (pReadBuffer == NULL)
  5303. {
  5304. TopChannel->FinishSubmitAsync();
  5305. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, RPC_S_OUT_OF_MEMORY);
  5306. return RPC_S_OUT_OF_MEMORY;
  5307. }
  5308. MaxReadBuffer = gPostSize;
  5309. }
  5310. else
  5311. {
  5312. ASSERT(iLastRead < MaxReadBuffer);
  5313. }
  5314. ReadsPending ++;
  5315. ASSERT(ReadsPending == 1);
  5316. BytesToTransfer = MaxReadBuffer - iLastRead;
  5317. Result = ControlBlock->ServerSupportFunction(ControlBlock->ConnID,
  5318. HSE_REQ_ASYNC_READ_CLIENT,
  5319. pReadBuffer + iLastRead,
  5320. &BytesToTransfer,
  5321. &IISIoFlags
  5322. );
  5323. TopChannel->FinishSubmitAsync();
  5324. if (Result == FALSE)
  5325. {
  5326. ReadsPending --;
  5327. ASSERT(ReadsPending == 0);
  5328. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5329. RpcStatus = RPC_P_RECEIVE_FAILED;
  5330. }
  5331. else
  5332. RpcStatus = RPC_S_OK;
  5333. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, RpcStatus);
  5334. return RpcStatus;
  5335. }
  5336. ULONG HTTP2IISTransportChannel::GetPostRuntimeEvent (
  5337. void
  5338. )
  5339. /*++
  5340. Routine Description:
  5341. Gets the message to be posted to the runtime.
  5342. Arguments:
  5343. Return Value:
  5344. The message to post to the runtime
  5345. --*/
  5346. {
  5347. return IN_PROXY_IIS_DIRECT_RECV;
  5348. }
  5349. /*********************************************************************
  5350. HTTP2IISSenderTransportChannel
  5351. *********************************************************************/
  5352. RPC_STATUS HTTP2IISSenderTransportChannel::Send (
  5353. IN OUT HTTP2SendContext *SendContext
  5354. )
  5355. /*++
  5356. Routine Description:
  5357. Send request
  5358. Arguments:
  5359. SendContext - the send context
  5360. Return Value:
  5361. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5362. --*/
  5363. {
  5364. BOOL Result;
  5365. ULONG LocalSendsPending;
  5366. RPC_STATUS RpcStatus;
  5367. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, (ULONG_PTR)SendContext);
  5368. Mutex.Request();
  5369. LocalSendsPending = SendsPending.Increment();
  5370. if ((LocalSendsPending > 1) || ReadsPending)
  5371. {
  5372. // queue and exit
  5373. SendContext->SetListEntryUsed();
  5374. RpcpInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  5375. Mutex.Clear();
  5376. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, 1);
  5377. return RPC_S_OK;
  5378. }
  5379. Mutex.Clear();
  5380. if (Direction == iistcdReceive)
  5381. ReverseDirection();
  5382. CurrentSendContext = SendContext;
  5383. BytesToTransfer = SendContext->maxWriteBuffer;
  5384. Result = ControlBlock->WriteClient(ControlBlock->ConnID,
  5385. SendContext->pWriteBuffer,
  5386. &BytesToTransfer,
  5387. IISIoFlags
  5388. );
  5389. if (Result == FALSE)
  5390. {
  5391. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5392. RpcStatus = RPC_P_SEND_FAILED;
  5393. }
  5394. else
  5395. RpcStatus = RPC_S_OK;
  5396. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, RpcStatus);
  5397. return RpcStatus;
  5398. }
  5399. RPC_STATUS HTTP2IISSenderTransportChannel::SendComplete (
  5400. IN RPC_STATUS EventStatus,
  5401. IN OUT HTTP2SendContext *SendContext
  5402. )
  5403. /*++
  5404. Routine Description:
  5405. Send complete notification
  5406. Arguments:
  5407. EventStatus - status of the operation
  5408. SendContext - the send context
  5409. Return Value:
  5410. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5411. --*/
  5412. {
  5413. ULONG LocalSendsPending;
  5414. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_IIS_SENDER_CHANNEL, EventStatus);
  5415. CurrentSendContext = NULL;
  5416. // decrement this in advance so that if we post another send on send
  5417. // complete, it doesn't get queued
  5418. LocalSendsPending = SendsPending.Decrement();
  5419. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  5420. if ((EventStatus == RPC_S_OK)
  5421. || (EventStatus == RPC_P_PACKET_CONSUMED) )
  5422. {
  5423. EventStatus = SendQueuedContextIfNecessary (LocalSendsPending, EventStatus);
  5424. }
  5425. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_IIS_SENDER_CHANNEL, EventStatus);
  5426. return AsyncCompleteHelper(EventStatus);
  5427. }
  5428. void HTTP2IISSenderTransportChannel::Abort (
  5429. IN RPC_STATUS RpcStatus
  5430. )
  5431. /*++
  5432. Routine Description:
  5433. Abort the channel
  5434. Arguments:
  5435. RpcStatus - the error code with which we abort
  5436. Return Value:
  5437. --*/
  5438. {
  5439. HTTP2SendContext *QueuedSendContext;
  5440. LIST_ENTRY *QueuedListEntry;
  5441. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_IIS_SENDER_CHANNEL, RpcStatus);
  5442. HTTP2IISTransportChannel::Abort(RpcStatus);
  5443. Mutex.Request();
  5444. if (SendsPending.GetInteger() > 1)
  5445. {
  5446. ASSERT(!RpcpIsListEmpty(&BufferQueueHead));
  5447. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  5448. do
  5449. {
  5450. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  5451. SendsPending.Decrement();
  5452. HTTP2TransportChannel::SendComplete(RpcStatus, QueuedSendContext);
  5453. TopChannel->RemoveReference();
  5454. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  5455. }
  5456. while (QueuedListEntry != &BufferQueueHead);
  5457. }
  5458. Mutex.Clear();
  5459. }
  5460. void HTTP2IISSenderTransportChannel::FreeObject (
  5461. void
  5462. )
  5463. /*++
  5464. Routine Description:
  5465. Frees the object. Acts like a destructor for the
  5466. channel.
  5467. Arguments:
  5468. Return Value:
  5469. --*/
  5470. {
  5471. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_IIS_SENDER_CHANNEL, 0);
  5472. FreeIISControlBlock();
  5473. HTTP2IISSenderTransportChannel::~HTTP2IISSenderTransportChannel();
  5474. }
  5475. RPC_STATUS HTTP2IISSenderTransportChannel::ReceiveCompleteInternal (
  5476. IN RPC_STATUS EventStatus,
  5477. IN HTTP2TrafficType TrafficType,
  5478. IN BOOL ReadCompleted,
  5479. IN OUT BYTE **Buffer,
  5480. IN OUT UINT *BufferLength
  5481. )
  5482. /*++
  5483. Routine Description:
  5484. Receive complete notification for the IIS sender transport channel. Somewhat
  5485. different signature than normal receive complete.
  5486. Arguments:
  5487. EventStatus - status of the operation
  5488. TrafficType - the type of traffic we have received
  5489. ReadCompleted - non-zero if a read completed. FALSE if it hasn't.
  5490. Buffer - the buffer. Must be NULL at this level on input. On
  5491. output contains the buffer for the current receive. If NULL
  5492. on output, we did not have a full packet. Undefined on failure.
  5493. BufferLength - the actual number of bytes received. On output the
  5494. number of bytes for the current packet. If 0 on output,
  5495. we did not have a complete packet. Undefined on failure.
  5496. Return Value:
  5497. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5498. --*/
  5499. {
  5500. RPC_STATUS RpcStatus;
  5501. ULONG LocalSendsPending;
  5502. Mutex.Request();
  5503. // decrease the reads pending and check the sends within the mutex -
  5504. // this ensures atomicity with respect to the send path's (which is
  5505. // the only path we race with) increase of the sends and check of the
  5506. // reads
  5507. if (ReadCompleted)
  5508. ReadsPending --;
  5509. ASSERT(ReadsPending == 0);
  5510. LocalSendsPending = SendsPending.GetInteger();
  5511. Mutex.Clear();
  5512. RpcStatus = HTTP2FragmentReceiver::ReceiveComplete (EventStatus,
  5513. TrafficType,
  5514. Buffer,
  5515. BufferLength
  5516. );
  5517. if ((RpcStatus == RPC_S_OK)
  5518. || (RpcStatus == RPC_P_PACKET_CONSUMED) )
  5519. {
  5520. RpcStatus = SendQueuedContextIfNecessary (LocalSendsPending, RpcStatus);
  5521. }
  5522. return RpcStatus;
  5523. }
  5524. RPC_STATUS HTTP2IISSenderTransportChannel::SendQueuedContextIfNecessary (
  5525. IN ULONG LocalSendsPending,
  5526. IN RPC_STATUS EventStatus
  5527. )
  5528. /*++
  5529. Routine Description:
  5530. Checks if any send contexts are queued for sending, and if yes, sends
  5531. the first one (which on completion will send the next, etc).
  5532. Arguments:
  5533. LocalSendsPending - the number of sends pending at the time the current
  5534. operation completed save for the count of the current operation (if it
  5535. was send)
  5536. EventStatus - the RPC Status so far. Must be a success error status
  5537. (RPC_S_OK or RPC_P_PACKET_CONSUMED)
  5538. Return Value:
  5539. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5540. --*/
  5541. {
  5542. HTTP2SendContext *QueuedSendContext;
  5543. LIST_ENTRY *QueuedListEntry;
  5544. BOOL Result;
  5545. if (LocalSendsPending != 0)
  5546. {
  5547. Mutex.Request();
  5548. if (Direction == iistcdReceive)
  5549. ReverseDirection();
  5550. QueuedListEntry = RpcpRemoveHeadList(&BufferQueueHead);
  5551. // it is possible that if an abort executed between getting LocalSendsPending
  5552. // in caller and grabbing the mutex here that the list is empty.
  5553. ASSERT(QueuedListEntry);
  5554. if (QueuedListEntry == &BufferQueueHead)
  5555. {
  5556. Mutex.Clear();
  5557. return EventStatus;
  5558. }
  5559. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  5560. Mutex.Clear();
  5561. QueuedSendContext->SetListEntryUnused();
  5562. // need to synchronize with aborts (rule 9)
  5563. EventStatus = TopChannel->BeginSimpleSubmitAsync();
  5564. if (EventStatus == RPC_S_OK)
  5565. {
  5566. CurrentSendContext = QueuedSendContext;
  5567. BytesToTransfer = QueuedSendContext->maxWriteBuffer;
  5568. Result = ControlBlock->WriteClient(ControlBlock->ConnID,
  5569. QueuedSendContext->pWriteBuffer,
  5570. &BytesToTransfer,
  5571. IISIoFlags
  5572. );
  5573. if (Result == FALSE)
  5574. {
  5575. EventStatus = RPC_P_SEND_FAILED;
  5576. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5577. // the send failed. We don't get a notification for it
  5578. // so we must issue one. Reference for the send we
  5579. // failed to post is already added
  5580. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, QueuedSendContext);
  5581. TopChannel->RemoveReference();
  5582. }
  5583. else
  5584. {
  5585. // must already be ok
  5586. ASSERT(EventStatus == RPC_S_OK);
  5587. }
  5588. TopChannel->FinishSubmitAsync();
  5589. }
  5590. }
  5591. return EventStatus;
  5592. }
  5593. /*********************************************************************
  5594. HTTP2GenericReceiver
  5595. *********************************************************************/
  5596. void HTTP2GenericReceiver::FreeObject (
  5597. void
  5598. )
  5599. /*++
  5600. Routine Description:
  5601. Frees the object. Acts like a destructor for the
  5602. channel.
  5603. Arguments:
  5604. Return Value:
  5605. --*/
  5606. {
  5607. if (LowerLayer)
  5608. LowerLayer->FreeObject();
  5609. HTTP2GenericReceiver::~HTTP2GenericReceiver();
  5610. }
  5611. void HTTP2GenericReceiver::TransferStateToNewReceiver (
  5612. OUT HTTP2GenericReceiver *NewReceiver
  5613. )
  5614. /*++
  5615. Routine Description:
  5616. Transfers all the settings from this receiver (i.e. the state
  5617. of the receive) to a new one.
  5618. Arguments:
  5619. NewReceiver - the new receiver to transfer the settings to
  5620. Return Value:
  5621. Notes:
  5622. This must be called in an upcall context (i.e. no real receives
  5623. pending) and the channel on which this is called must be non-default
  5624. by now.
  5625. --*/
  5626. {
  5627. NewReceiver->ReceiveWindow = ReceiveWindow;
  5628. }
  5629. RPC_STATUS HTTP2GenericReceiver::BytesReceivedNotification (
  5630. IN ULONG Bytes
  5631. )
  5632. /*++
  5633. Routine Description:
  5634. Notifies channel that bytes have been received.
  5635. Arguments:
  5636. Bytes - the number of data bytes received.
  5637. Return Value:
  5638. RPC_S_OK if the received bytes did not violate the
  5639. flow control protocol. RPC_S_PROTOCOL error otherwise.
  5640. --*/
  5641. {
  5642. Mutex.VerifyOwned();
  5643. BytesReceived += Bytes;
  5644. BytesInWindow += Bytes;
  5645. ASSERT(BytesInWindow <= ReceiveWindow);
  5646. FreeWindowAdvertised -= Bytes;
  5647. if (FreeWindowAdvertised < 0)
  5648. {
  5649. ASSERT(0);
  5650. // sender sent data even though
  5651. // we told it we don't have enough window
  5652. // to receive it - protocol violation
  5653. return RPC_S_PROTOCOL_ERROR;
  5654. }
  5655. return RPC_S_OK;
  5656. }
  5657. void HTTP2GenericReceiver::BytesConsumedNotification (
  5658. IN ULONG Bytes,
  5659. IN BOOL OwnsMutex,
  5660. OUT BOOL *IssueAck,
  5661. OUT ULONG *BytesReceivedForAck,
  5662. OUT ULONG *WindowForAck
  5663. )
  5664. /*++
  5665. Routine Description:
  5666. Notifies channel that bytes have been consumed and can
  5667. be freed from the receive window of the channel.
  5668. Arguments:
  5669. Bytes - the number of data bytes consumed.
  5670. OwnsMutex - non-zero if the mutex for the channel is
  5671. already owned.
  5672. IssueAck - must be FALSE on input. If the caller needs
  5673. to issue an Ack, it will be set to non-zero on
  5674. output.
  5675. BytesReceivedForAck - on output, if IssueAck is non-zero,
  5676. it will contain the bytes received to put in the
  5677. ack packet. If IssueAck is FALSE, it is undefined.
  5678. WindowForAck - on output, if IssueAck is non-zero,
  5679. it will contain the window available to put in the
  5680. ack packet. If IssueAck is FALSE, it is undefined.
  5681. Return Value:
  5682. --*/
  5683. {
  5684. ULONG ReceiveWindowThreshold;
  5685. if (OwnsMutex)
  5686. {
  5687. Mutex.VerifyOwned();
  5688. }
  5689. else
  5690. {
  5691. Mutex.Request();
  5692. }
  5693. ASSERT(*IssueAck == FALSE);
  5694. BytesInWindow -= Bytes;
  5695. // make sure we don't wrap
  5696. ASSERT(BytesInWindow <= ReceiveWindow);
  5697. ReceiveWindowThreshold = ReceiveWindow >> 1;
  5698. if (FreeWindowAdvertised < (LONG)ReceiveWindowThreshold)
  5699. {
  5700. // we fell below the threshold. ACK our current window
  5701. *IssueAck = TRUE;
  5702. FreeWindowAdvertised = ReceiveWindow - BytesInWindow;
  5703. ASSERT(FreeWindowAdvertised >= 0);
  5704. *BytesReceivedForAck = BytesReceived;
  5705. *WindowForAck = FreeWindowAdvertised;
  5706. }
  5707. if (OwnsMutex == FALSE)
  5708. {
  5709. Mutex.Clear();
  5710. }
  5711. }
  5712. RPC_STATUS HTTP2GenericReceiver::SendFlowControlAck (
  5713. IN ULONG BytesReceivedForAck,
  5714. IN ULONG WindowForAck
  5715. )
  5716. /*++
  5717. Routine Description:
  5718. Sends a flow control Ack packet.
  5719. Arguments:
  5720. BytesReceivedForAck - the number of bytes received while
  5721. we were issuing the Ack
  5722. WindowForAck - the window available when BytesReceivedForAck
  5723. bytes have been received
  5724. Return Value:
  5725. RPC_S_OK or RPC_S_* for error
  5726. Notes:
  5727. This must be called in a neutral context.
  5728. --*/
  5729. {
  5730. return TopChannel->ForwardFlowControlAck (BytesReceivedForAck,
  5731. WindowForAck
  5732. );
  5733. }
  5734. /*********************************************************************
  5735. HTTP2EndpointReceiver
  5736. *********************************************************************/
  5737. RPC_STATUS HTTP2EndpointReceiver::Receive (
  5738. IN HTTP2TrafficType TrafficType
  5739. )
  5740. /*++
  5741. Routine Description:
  5742. Receive request
  5743. Arguments:
  5744. TrafficType - the type of traffic we want to receive
  5745. Return Value:
  5746. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5747. --*/
  5748. {
  5749. BOOL PostReceive;
  5750. RPC_STATUS RpcStatus;
  5751. BOOL DequeuePacket;
  5752. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, TrafficType);
  5753. DequeuePacket = FALSE;
  5754. PostReceive = FALSE;
  5755. Mutex.Request();
  5756. switch (TrafficType)
  5757. {
  5758. case http2ttNone:
  5759. ASSERT(0);
  5760. RpcStatus = RPC_S_INTERNAL_ERROR;
  5761. Mutex.Clear();
  5762. return RpcStatus;
  5763. case http2ttRTS:
  5764. // we cannot issue two RTS receives.
  5765. ASSERT((ReceivesPosted & http2ttRTS) == 0);
  5766. // if we have RTS receives queued, dequeue one and
  5767. // complete it
  5768. if (ReceivesQueued == http2ttRTS)
  5769. {
  5770. ASSERT(DirectCompletePosted == FALSE);
  5771. DirectCompletePosted = TRUE;
  5772. DequeuePacket = TRUE;
  5773. }
  5774. else
  5775. {
  5776. // we have no packets queued, or only data packets
  5777. // queued. If we have no data request pending, create
  5778. // a request pending. Otherwise just add ourselves to
  5779. // the map
  5780. if (ReceivesPosted)
  5781. {
  5782. ASSERT(ReceivesPosted == http2ttData);
  5783. ReceivesPosted = http2ttAny;
  5784. }
  5785. else
  5786. {
  5787. PostReceive = TRUE;
  5788. ReceivesPosted = http2ttRTS;
  5789. }
  5790. }
  5791. break;
  5792. case http2ttData:
  5793. // we cannot issue two Data receives.
  5794. ASSERT((ReceivesPosted & http2ttData) == 0);
  5795. // if we have Data receives queued, dequeue one and
  5796. // complete it
  5797. if (ReceivesQueued == http2ttData)
  5798. {
  5799. ASSERT(DirectCompletePosted == FALSE);
  5800. DirectCompletePosted = TRUE;
  5801. DequeuePacket = TRUE;
  5802. }
  5803. else
  5804. {
  5805. // we have no packets queued, or only RTS packets
  5806. // queued. If we have no RTS request pending, create
  5807. // a request pending. Otherwise just add ourselves to
  5808. // the map
  5809. if (ReceivesPosted)
  5810. {
  5811. ASSERT(ReceivesPosted == http2ttRTS);
  5812. ReceivesPosted = http2ttAny;
  5813. }
  5814. else
  5815. {
  5816. PostReceive = TRUE;
  5817. ReceivesPosted = http2ttData;
  5818. }
  5819. }
  5820. break;
  5821. default:
  5822. ASSERT(0);
  5823. RpcStatus = RPC_S_INTERNAL_ERROR;
  5824. Mutex.Clear();
  5825. return RpcStatus;
  5826. }
  5827. // only one of PostReceive and DequeuePacket can be set here.
  5828. // Neither is ok too.
  5829. ASSERT((PostReceive ^ DequeuePacket)
  5830. || ((PostReceive == FALSE)
  5831. &&
  5832. (DequeuePacket == FALSE)
  5833. )
  5834. );
  5835. Mutex.Clear();
  5836. if (DequeuePacket)
  5837. {
  5838. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 0);
  5839. (void) COMMON_PostRuntimeEvent(HTTP2_DIRECT_RECEIVE,
  5840. this
  5841. );
  5842. return RPC_S_OK;
  5843. }
  5844. if (PostReceive == FALSE)
  5845. {
  5846. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 1);
  5847. return RPC_S_OK;
  5848. }
  5849. RpcStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  5850. if (RpcStatus != RPC_S_OK)
  5851. {
  5852. // we have indicated our receive as pending, yet we
  5853. // couldn't submit it. Not good. Must attempt to
  5854. // remove it from the pending variable unless somebody
  5855. // else already did (which is possible if we wanted
  5856. // to submit data and there was already pending RTS).
  5857. Mutex.Request();
  5858. switch (ReceivesPosted)
  5859. {
  5860. case http2ttNone:
  5861. // should not be possible
  5862. ASSERT(FALSE);
  5863. RpcStatus = RPC_S_INTERNAL_ERROR;
  5864. Mutex.Clear();
  5865. return RpcStatus;
  5866. case http2ttData:
  5867. if (TrafficType == http2ttData)
  5868. ReceivesPosted = http2ttNone;
  5869. else
  5870. {
  5871. // not possible that we submitted RTS
  5872. // and have data pending but not RTS
  5873. ASSERT(0);
  5874. Mutex.Clear();
  5875. return RPC_S_INTERNAL_ERROR;
  5876. }
  5877. break;
  5878. case http2ttRTS:
  5879. if (TrafficType == http2ttRTS)
  5880. ReceivesPosted = http2ttNone;
  5881. else
  5882. {
  5883. // possible that we attempted to submit data,
  5884. // but while we were trying, an async RTS submission
  5885. // failed, and we indicated it asynchronously. In this
  5886. // case we must not indicate the failure synchronously
  5887. RpcStatus = RPC_S_OK;
  5888. }
  5889. break;
  5890. case http2ttAny:
  5891. if (TrafficType == http2ttRTS)
  5892. ReceivesPosted = http2ttData;
  5893. else
  5894. ReceivesPosted = http2ttRTS;
  5895. break;
  5896. default:
  5897. ASSERT(0);
  5898. Mutex.Clear();
  5899. return RPC_S_INTERNAL_ERROR;
  5900. }
  5901. Mutex.Clear();
  5902. }
  5903. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 3);
  5904. return RpcStatus;
  5905. }
  5906. RPC_STATUS HTTP2EndpointReceiver::ReceiveComplete (
  5907. IN RPC_STATUS EventStatus,
  5908. IN HTTP2TrafficType TrafficType,
  5909. IN BYTE *Buffer,
  5910. IN UINT BufferLength
  5911. )
  5912. /*++
  5913. Routine Description:
  5914. Receive complete notification.
  5915. Arguments:
  5916. EventStatus - status of the operation
  5917. TrafficType - the type of traffic we have received
  5918. Buffer - the received buffer (success only)
  5919. BufferLength - the length of the received buffer (success only)
  5920. Return Value:
  5921. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5922. --*/
  5923. {
  5924. HTTP2TrafficType NewReceivesPosted;
  5925. HTTP2TrafficType ThisCompleteTrafficType;
  5926. RPC_STATUS RpcStatus;
  5927. RPC_STATUS RpcStatus2;
  5928. BOOL BufferQueued;
  5929. RPC_STATUS RTSStatus;
  5930. RPC_STATUS DataStatus;
  5931. BOOL ReceiveCompletesFailed;
  5932. BYTE *CurrentPosition;
  5933. USHORT PacketFlags;
  5934. BOOL IssueAck;
  5935. ULONG BytesReceivedForAck;
  5936. ULONG WindowForAck;
  5937. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, EventStatus);
  5938. BufferQueued = FALSE;
  5939. Mutex.Request();
  5940. if (EventStatus == RPC_S_OK)
  5941. {
  5942. if (IsRTSPacket(Buffer))
  5943. ThisCompleteTrafficType = http2ttRTS;
  5944. else
  5945. {
  5946. ThisCompleteTrafficType = http2ttData;
  5947. EventStatus = BytesReceivedNotification(BufferLength
  5948. );
  5949. if (EventStatus != RPC_S_OK)
  5950. {
  5951. // fall through with an error. Don't free the buffer
  5952. // (Rule 34).
  5953. }
  5954. }
  5955. }
  5956. if (EventStatus != RPC_S_OK)
  5957. {
  5958. if (ReceivesPosted == http2ttAny)
  5959. ThisCompleteTrafficType = http2ttData;
  5960. else
  5961. ThisCompleteTrafficType = ReceivesPosted;
  5962. }
  5963. ReceiveCompletesFailed = FALSE;
  5964. switch (ThisCompleteTrafficType)
  5965. {
  5966. case http2ttData:
  5967. if ((ReceivesPosted & http2ttData) == FALSE)
  5968. {
  5969. // we haven't asked for data, but we get some. We'll
  5970. // have to queue it
  5971. ASSERT(ReceivesQueued != http2ttRTS);
  5972. ReceivesQueued = http2ttData;
  5973. if (BufferQueue.PutOnQueue(Buffer, BufferLength))
  5974. {
  5975. ReceiveCompletesFailed = TRUE;
  5976. RpcFreeBuffer(Buffer);
  5977. }
  5978. BufferQueued = TRUE;
  5979. }
  5980. else
  5981. {
  5982. ReceivesPosted = (HTTP2TrafficType)(ReceivesPosted ^ http2ttData);
  5983. NewReceivesPosted = ReceivesPosted;
  5984. }
  5985. break;
  5986. case http2ttRTS:
  5987. if ((ReceivesPosted & http2ttRTS) == FALSE)
  5988. {
  5989. // we haven't asked for RTS, but we get some. We'll
  5990. // have to queue it
  5991. ASSERT(ReceivesQueued != http2ttData);
  5992. ReceivesQueued = http2ttRTS;
  5993. if (BufferQueue.PutOnQueue(Buffer, BufferLength))
  5994. {
  5995. ReceiveCompletesFailed = TRUE;
  5996. RpcFreeBuffer(Buffer);
  5997. }
  5998. BufferQueued = TRUE;
  5999. }
  6000. else
  6001. {
  6002. ReceivesPosted = (HTTP2TrafficType)(ReceivesPosted ^ http2ttRTS);
  6003. NewReceivesPosted = ReceivesPosted;
  6004. }
  6005. break;
  6006. default:
  6007. ASSERT(0);
  6008. break;
  6009. }
  6010. IssueAck = FALSE;
  6011. if ((BufferQueued == FALSE)
  6012. && (ReceiveCompletesFailed == FALSE)
  6013. && (ThisCompleteTrafficType == http2ttData)
  6014. && (EventStatus == RPC_S_OK))
  6015. {
  6016. // we know the data will be consumed immediately
  6017. BytesConsumedNotification (BufferLength,
  6018. TRUE, // OwnsMutex
  6019. &IssueAck,
  6020. &BytesReceivedForAck,
  6021. &WindowForAck
  6022. );
  6023. }
  6024. Mutex.Clear();
  6025. if (IssueAck)
  6026. {
  6027. RpcStatus = SendFlowControlAck (BytesReceivedForAck,
  6028. WindowForAck
  6029. );
  6030. if (RpcStatus != RPC_S_OK)
  6031. {
  6032. // turn this into a failure
  6033. EventStatus = RpcStatus;
  6034. // fall through to issuing the notification
  6035. if (EventStatus == RPC_P_SEND_FAILED)
  6036. EventStatus = RPC_P_RECEIVE_FAILED;
  6037. }
  6038. }
  6039. if (ReceiveCompletesFailed)
  6040. {
  6041. // we got an unwanted receive, and couldn't queue it.
  6042. // Abort the connection
  6043. TopChannel->AbortConnection(RPC_S_OUT_OF_MEMORY);
  6044. return RPC_P_PACKET_CONSUMED;
  6045. }
  6046. if (BufferQueued)
  6047. {
  6048. ASSERT(ReceivesPosted != http2ttNone);
  6049. // the packet was not of the type we wanted.
  6050. // Submit another receive hoping to get what we want
  6051. RpcStatus = TopChannel->BeginSubmitAsync();
  6052. if (RpcStatus == RPC_S_OK)
  6053. {
  6054. // we know we have one type of receive in the map. Nobody
  6055. // can post another. Just post ours
  6056. RpcStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  6057. TopChannel->FinishSubmitAsync();
  6058. if (RpcStatus != RPC_S_OK)
  6059. {
  6060. TopChannel->RemoveReference();
  6061. }
  6062. }
  6063. if (RpcStatus != RPC_S_OK)
  6064. {
  6065. // we failed to submit the receive. We have to issue notification for it
  6066. RpcStatus = HTTP2TransportChannel::ReceiveComplete(RpcStatus,
  6067. ReceivesPosted,
  6068. NULL, // Buffer
  6069. 0 // BufferLength
  6070. );
  6071. TopChannel->AbortConnection(RpcStatus);
  6072. }
  6073. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RPC_P_PACKET_CONSUMED);
  6074. // if we have queued, this means the runtime did not
  6075. // ask for this packet. Don't let it see it.
  6076. return RPC_P_PACKET_CONSUMED;
  6077. }
  6078. // The buffer was not queued - pass it up
  6079. RpcStatus = HTTP2TransportChannel::ReceiveComplete(EventStatus,
  6080. ThisCompleteTrafficType,
  6081. Buffer,
  6082. BufferLength
  6083. );
  6084. if (NewReceivesPosted != http2ttNone)
  6085. {
  6086. // if we left something in the map, nobody could have
  6087. // posted a raw receive - they would have just upgraded the
  6088. // map. It could still have been aborted though
  6089. ASSERT((NewReceivesPosted == http2ttRTS)
  6090. ||
  6091. (NewReceivesPosted == http2ttData));
  6092. // see what was left as pending recieve, and
  6093. // actually submit that. We do that only if we didn't
  6094. // fail before. If we did, don't bother
  6095. if (EventStatus == RPC_S_OK)
  6096. {
  6097. RpcStatus2 = TopChannel->BeginSimpleSubmitAsync();
  6098. if (RpcStatus2 == RPC_S_OK)
  6099. {
  6100. RpcStatus2 = HTTP2TransportChannel::Receive(http2ttRaw);
  6101. TopChannel->FinishSubmitAsync();
  6102. }
  6103. }
  6104. else
  6105. {
  6106. // transfer the error code
  6107. RpcStatus2 = EventStatus;
  6108. }
  6109. if (RpcStatus2 != RPC_S_OK)
  6110. {
  6111. // we failed to submit the receive. We have to issue notification for it
  6112. RpcStatus2 = HTTP2TransportChannel::ReceiveComplete(RpcStatus2,
  6113. NewReceivesPosted,
  6114. NULL, // Buffer
  6115. 0 // BufferLength
  6116. );
  6117. if (NewReceivesPosted == http2ttRTS)
  6118. {
  6119. ASSERT(RpcStatus2 != RPC_S_OK);
  6120. }
  6121. TopChannel->RemoveReference(); // remove reference for the receive complete
  6122. }
  6123. }
  6124. // here, ThisCompleteTrafficType is the type of completed receive and
  6125. // RpcStatus is the status for it. NewReceivesPosted is the next submit we received
  6126. // (http2ttNone if none) and RpcStatus2 is the status for it.
  6127. // make sure nobody has left unconsumed success RTS packets
  6128. if (ThisCompleteTrafficType == http2ttRTS)
  6129. {
  6130. ASSERT(RpcStatus != RPC_S_OK);
  6131. }
  6132. // if there is only one receive type, no merging is necessary - just return
  6133. if (NewReceivesPosted == http2ttNone)
  6134. {
  6135. // consume RTS receives
  6136. if (ThisCompleteTrafficType == http2ttRTS)
  6137. RpcStatus = RPC_P_PACKET_CONSUMED;
  6138. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6139. return RpcStatus;
  6140. }
  6141. // Process them and determine the appropriate return code. If we
  6142. // have two receives, we merge them as per the table below
  6143. // N First Receive Second Receive Return value Note
  6144. // -- -------------- ----------------- ------------- ---------
  6145. // 1 DS RS S
  6146. // 2 DS RC S
  6147. // 3 DS RF S Abort
  6148. // 4 DF RS F
  6149. // 5 DF RC F
  6150. // 6 DF RF F Choose first receive error
  6151. // 7 RS DS Invalid combination (first RTS should have been consumed)
  6152. // 8 RC DS C
  6153. // 9 RF DS S Abort
  6154. // 10 RS DF Invalid combination (first RTS should have been consumed)
  6155. // 11 RC DF C Abort
  6156. // 12 RF DF F Choose first receive error
  6157. if (ThisCompleteTrafficType == http2ttData)
  6158. {
  6159. ASSERT(NewReceivesPosted == http2ttRTS);
  6160. DataStatus = RpcStatus;
  6161. RTSStatus = RpcStatus2;
  6162. }
  6163. else
  6164. {
  6165. ASSERT(NewReceivesPosted == http2ttData);
  6166. DataStatus = RpcStatus2;
  6167. RTSStatus = RpcStatus;
  6168. }
  6169. if (DataStatus == RPC_S_OK)
  6170. {
  6171. if (RTSStatus == RPC_S_OK)
  6172. {
  6173. // case 1 - just return ok
  6174. RpcStatus = RTSStatus;
  6175. }
  6176. else if (RTSStatus == RPC_P_PACKET_CONSUMED)
  6177. {
  6178. // case 2
  6179. if (ThisCompleteTrafficType == http2ttData)
  6180. {
  6181. RpcStatus = DataStatus;
  6182. }
  6183. else
  6184. {
  6185. // case 8
  6186. RpcStatus = RTSStatus;
  6187. }
  6188. }
  6189. else
  6190. {
  6191. // cases 3 & 9
  6192. TopChannel->AbortConnection(RTSStatus);
  6193. }
  6194. }
  6195. else
  6196. {
  6197. if (RTSStatus == RPC_S_OK)
  6198. {
  6199. // case 4
  6200. RpcStatus = DataStatus;
  6201. }
  6202. else if (RTSStatus == RPC_P_PACKET_CONSUMED)
  6203. {
  6204. // case 5
  6205. if (ThisCompleteTrafficType == http2ttData)
  6206. {
  6207. RpcStatus = DataStatus;
  6208. }
  6209. else
  6210. {
  6211. // case 11
  6212. TopChannel->AbortConnection(DataStatus);
  6213. RpcStatus = RTSStatus;
  6214. }
  6215. }
  6216. else
  6217. {
  6218. // cases 6 & 12
  6219. // nothing to do. First error is already in RpcStatus
  6220. }
  6221. }
  6222. if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  6223. RpcStatus = RPC_P_RECEIVE_FAILED;
  6224. VALIDATE (RpcStatus)
  6225. {
  6226. RPC_S_OK,
  6227. RPC_P_PACKET_CONSUMED,
  6228. RPC_P_RECEIVE_FAILED
  6229. } END_VALIDATE;
  6230. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6231. return RpcStatus;
  6232. }
  6233. void HTTP2EndpointReceiver::Abort (
  6234. IN RPC_STATUS RpcStatus
  6235. )
  6236. /*++
  6237. Routine Description:
  6238. Abort the channel
  6239. Arguments:
  6240. RpcStatus - the error code with which we abort
  6241. Return Value:
  6242. --*/
  6243. {
  6244. BYTE *CurrentBuffer;
  6245. UINT Ignored;
  6246. ULONG SizeOfQueueToLeave;
  6247. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6248. HTTP2TransportChannel::Abort(RpcStatus);
  6249. Mutex.Request();
  6250. // if there is a direct complete posted, we have to
  6251. // leave one element in the queue, because the
  6252. // direct complete routine will need it
  6253. if (DirectCompletePosted)
  6254. SizeOfQueueToLeave = 1;
  6255. else
  6256. SizeOfQueueToLeave = 0;
  6257. while (BufferQueue.Size() > SizeOfQueueToLeave)
  6258. {
  6259. CurrentBuffer = (BYTE *) BufferQueue.TakeOffEndOfQueue(&Ignored);
  6260. // the elements in the queue are unwanted anyway -
  6261. // they don't have refcounts or anything else - just
  6262. // free them
  6263. RpcFreeBuffer(CurrentBuffer);
  6264. }
  6265. Mutex.Clear();
  6266. }
  6267. void HTTP2EndpointReceiver::FreeObject (
  6268. void
  6269. )
  6270. /*++
  6271. Routine Description:
  6272. Frees the object. Acts like a destructor for the
  6273. channel.
  6274. Arguments:
  6275. Return Value:
  6276. --*/
  6277. {
  6278. if (LowerLayer)
  6279. LowerLayer->FreeObject();
  6280. HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  6281. }
  6282. RPC_STATUS HTTP2EndpointReceiver::DirectReceiveComplete (
  6283. OUT BYTE **ReceivedBuffer,
  6284. OUT ULONG *ReceivedBufferLength,
  6285. OUT void **RuntimeConnection,
  6286. OUT BOOL *IsServer
  6287. )
  6288. /*++
  6289. Routine Description:
  6290. Direct receive completion (i.e. we posted a receive
  6291. to ourselves). We can be called in only one case -
  6292. a receive was submitted and there were already
  6293. queued receives.
  6294. Arguments:
  6295. ReceivedBuffer - the buffer that we received.
  6296. ReceivedBufferLength - the length of the received
  6297. buffer
  6298. RuntimeConnection - the connection to return to the runtime
  6299. if the packet is not consumed.
  6300. IsServer - non-zero if the server
  6301. Return Value:
  6302. RPC_S_OK, RPC_P_PACKET_CONSUMED or RPC_S_* errors.
  6303. Notes:
  6304. The directly posted receive carries a reference count
  6305. --*/
  6306. {
  6307. BYTE *Buffer;
  6308. ULONG BufferLength;
  6309. RPC_STATUS RpcStatus;
  6310. HTTP2TrafficType QueuedPacketsType;
  6311. BOOL IssueAck;
  6312. ULONG BytesReceivedForAck;
  6313. ULONG WindowForAck;
  6314. BOOL PacketNeedsFlowControl;
  6315. *IsServer = this->IsServer;
  6316. *RuntimeConnection = TopChannel->GetRuntimeConnection();
  6317. // dequeue a packet
  6318. // we cannot have a queue and a posted receive at the same time
  6319. ASSERT((ReceivesPosted & ReceivesQueued) == FALSE);
  6320. Mutex.Request();
  6321. ASSERT(DirectCompletePosted);
  6322. ASSERT(DirectReceiveInProgress == FALSE);
  6323. // they must be set in this order, because if a thread in
  6324. // TransferStateToNewReceiver synchronizes with us, it will check
  6325. // them in reverse order.
  6326. InterlockedIncrement((long *)&DirectReceiveInProgress);
  6327. DirectCompletePosted = FALSE;
  6328. QueuedPacketsType = ReceivesQueued;
  6329. Buffer = (BYTE *)BufferQueue.TakeOffQueue((UINT *)&BufferLength);
  6330. // even if aborted, at least one buffer must have been left for us
  6331. // because we had the DirectCompletePosted flag set
  6332. ASSERT (Buffer);
  6333. if (BufferQueue.IsQueueEmpty())
  6334. ReceivesQueued = http2ttNone;
  6335. PacketNeedsFlowControl = (((ULONG_PTR)Buffer & 1) == 0);
  6336. Buffer = (BYTE *)(((ULONG_PTR)Buffer) & (~(ULONG_PTR)1));
  6337. RpcStatus = RPC_S_OK;
  6338. *ReceivedBuffer = Buffer;
  6339. *ReceivedBufferLength = BufferLength;
  6340. // we know the data will be consumed.
  6341. IssueAck = FALSE;
  6342. if ((QueuedPacketsType == http2ttData) && PacketNeedsFlowControl)
  6343. {
  6344. BytesConsumedNotification (BufferLength,
  6345. TRUE, // OwnsMutex
  6346. &IssueAck,
  6347. &BytesReceivedForAck,
  6348. &WindowForAck
  6349. );
  6350. }
  6351. Mutex.Clear();
  6352. if (IssueAck)
  6353. {
  6354. RpcStatus = SendFlowControlAck (BytesReceivedForAck,
  6355. WindowForAck
  6356. );
  6357. if (RpcStatus != RPC_S_OK)
  6358. {
  6359. // turn this into a failure. Note that we must supply a buffer
  6360. // on failure, hence we don't free it (Rule 34)
  6361. // fall through to issuing the notification
  6362. }
  6363. }
  6364. // decrement if before receive complete. In receive complete
  6365. // we may post another receive and cause a race
  6366. InterlockedDecrement((long *)&DirectReceiveInProgress);
  6367. RpcStatus = HTTP2TransportChannel::ReceiveComplete(RpcStatus,
  6368. QueuedPacketsType,
  6369. Buffer,
  6370. BufferLength
  6371. );
  6372. if (QueuedPacketsType == http2ttRTS)
  6373. {
  6374. ASSERT(RpcStatus != RPC_S_OK);
  6375. RpcStatus = RPC_P_PACKET_CONSUMED;
  6376. }
  6377. else
  6378. {
  6379. if (RpcStatus == RPC_P_SEND_FAILED)
  6380. RpcStatus = RPC_P_RECEIVE_FAILED;
  6381. }
  6382. RpcStatus = AsyncCompleteHelper(RpcStatus);
  6383. VALIDATE(RpcStatus)
  6384. {
  6385. RPC_P_CONNECTION_CLOSED,
  6386. RPC_P_RECEIVE_FAILED,
  6387. RPC_P_CONNECTION_SHUTDOWN,
  6388. RPC_P_PACKET_CONSUMED,
  6389. RPC_S_OK
  6390. } END_VALIDATE;
  6391. return RpcStatus;
  6392. }
  6393. RPC_STATUS HTTP2EndpointReceiver::TransferStateToNewReceiver (
  6394. OUT HTTP2EndpointReceiver *NewReceiver
  6395. )
  6396. /*++
  6397. Routine Description:
  6398. Transfers all the settings from this receiver (i.e. the state
  6399. of the receive) to a new one.
  6400. Arguments:
  6401. NewReceiver - the new receiver to transfer the settings to
  6402. Return Value:
  6403. RPC_S_OK or RPC_S_* errors.
  6404. Notes:
  6405. This must be called in an upcall context (i.e. no real receives
  6406. pending) and the channel on which this is called must be non-default
  6407. by now.
  6408. --*/
  6409. {
  6410. void *Buffer;
  6411. UINT BufferLength;
  6412. void *QueueElement;
  6413. int Result;
  6414. BOOL QueueTransferred;
  6415. // this channel is not a default channel by now. We know that
  6416. // there may be receives in progress, but no new receives will be
  6417. // submitted.
  6418. while (TRUE)
  6419. {
  6420. Mutex.Request();
  6421. if (DirectCompletePosted || DirectReceiveInProgress)
  6422. {
  6423. Mutex.Clear();
  6424. Sleep(5);
  6425. }
  6426. else
  6427. break;
  6428. }
  6429. NewReceiver->Mutex.Request();
  6430. // transfer the settings for the base class
  6431. HTTP2GenericReceiver::TransferStateToNewReceiver(NewReceiver);
  6432. if (NewReceiver->BufferQueue.IsQueueEmpty() == FALSE)
  6433. {
  6434. // the only way we can end up here is if the channel replacement
  6435. // took so long that the peer started pinging us. This is a protocol
  6436. // error.
  6437. NewReceiver->Mutex.Clear();
  6438. Mutex.Clear();
  6439. return RPC_S_PROTOCOL_ERROR;
  6440. }
  6441. QueueTransferred = FALSE;
  6442. while (TRUE)
  6443. {
  6444. QueueElement = BufferQueue.TakeOffEndOfQueue(&BufferLength);
  6445. if (QueueElement == 0)
  6446. {
  6447. QueueTransferred = TRUE;
  6448. break;
  6449. }
  6450. if (NewReceiver->BufferQueue.PutOnFrontOfQueue((void *)((ULONG_PTR)QueueElement | 1), BufferLength) != 0)
  6451. {
  6452. // guaranteed to succeed since we never decrease buffers
  6453. BufferQueue.PutOnFrontOfQueue(QueueElement, BufferLength);
  6454. break;
  6455. }
  6456. }
  6457. if (QueueTransferred == FALSE)
  6458. {
  6459. // failure - out of memory. Since the buffers are unwanted
  6460. // we can just return failure. Both channels will be
  6461. // aborted
  6462. NewReceiver->Mutex.Clear();
  6463. Mutex.Clear();
  6464. return RPC_S_OUT_OF_MEMORY;
  6465. }
  6466. NewReceiver->ReceivesQueued = ReceivesQueued;
  6467. // we never transfer data receives. They will be transferred by our caller
  6468. // We also preserve existing receives on the new receiver. There is a race where
  6469. // data receives may have ended up on the new channel. That's ok as long as they
  6470. // are off the old.
  6471. ASSERT(((NewReceiver->ReceivesPosted & http2ttData) == 0)
  6472. || ((ReceivesPosted & http2ttData) == 0));
  6473. NewReceiver->ReceivesPosted
  6474. = (HTTP2TrafficType)(NewReceiver->ReceivesPosted | (ReceivesPosted & (~http2ttData)));
  6475. // direct complete posted cannot be true here
  6476. ASSERT(DirectCompletePosted == FALSE);
  6477. NewReceiver->Mutex.Clear();
  6478. Mutex.Clear();
  6479. return RPC_S_OK;
  6480. }
  6481. /*********************************************************************
  6482. HTTP2ProxyReceiver
  6483. *********************************************************************/
  6484. RPC_STATUS HTTP2ProxyReceiver::ReceiveComplete (
  6485. IN RPC_STATUS EventStatus,
  6486. IN HTTP2TrafficType TrafficType,
  6487. IN BYTE *Buffer,
  6488. IN UINT BufferLength
  6489. )
  6490. /*++
  6491. Routine Description:
  6492. Receive complete notification.
  6493. Arguments:
  6494. EventStatus - status of the operation
  6495. TrafficType - the type of traffic we have received
  6496. Buffer - the received buffer (success only)
  6497. BufferLength - the length of the received buffer (success only)
  6498. Return Value:
  6499. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6500. --*/
  6501. {
  6502. if ((EventStatus == RPC_S_OK) && (IsRTSPacket(Buffer) == FALSE))
  6503. {
  6504. Mutex.Request();
  6505. EventStatus = BytesReceivedNotification(BufferLength
  6506. );
  6507. Mutex.Clear();
  6508. if (EventStatus != RPC_S_OK)
  6509. {
  6510. // consume the packet and fall through with an error
  6511. RpcFreeBuffer(Buffer);
  6512. }
  6513. }
  6514. return HTTP2TransportChannel::ReceiveComplete(EventStatus,
  6515. TrafficType,
  6516. Buffer,
  6517. BufferLength
  6518. );
  6519. }
  6520. void HTTP2ProxyReceiver::Abort (
  6521. IN RPC_STATUS RpcStatus
  6522. )
  6523. /*++
  6524. Routine Description:
  6525. Abort the channel.
  6526. Arguments:
  6527. RpcStatus - the error code with which we abort
  6528. Return Value:
  6529. --*/
  6530. {
  6531. BYTE *CurrentBuffer;
  6532. UINT Ignored;
  6533. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PROXY_RECEIVER, RpcStatus);
  6534. HTTP2TransportChannel::Abort(RpcStatus);
  6535. Mutex.Request();
  6536. while (BufferQueue.Size() > 0)
  6537. {
  6538. CurrentBuffer = (BYTE *) BufferQueue.TakeOffQueue(&Ignored);
  6539. // the elements in the queue are unwanted anyway -
  6540. // they don't have refcounts or anything else - just
  6541. // free them
  6542. RpcFreeBuffer(CurrentBuffer);
  6543. }
  6544. Mutex.Clear();
  6545. }
  6546. void HTTP2ProxyReceiver::FreeObject (
  6547. void
  6548. )
  6549. /*++
  6550. Routine Description:
  6551. Frees the object. Acts like a destructor for the
  6552. channel.
  6553. Arguments:
  6554. Return Value:
  6555. --*/
  6556. {
  6557. if (LowerLayer)
  6558. LowerLayer->FreeObject();
  6559. HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  6560. }
  6561. /*********************************************************************
  6562. HTTP2PlugChannel
  6563. *********************************************************************/
  6564. C_ASSERT(http2plRTSPlugged == http2ttRTS);
  6565. C_ASSERT(http2plDataPlugged == http2ttData);
  6566. RPC_STATUS HTTP2PlugChannel::Send (
  6567. IN OUT HTTP2SendContext *SendContext
  6568. )
  6569. /*++
  6570. Routine Description:
  6571. Send request
  6572. Arguments:
  6573. SendContext - the send context
  6574. Return Value:
  6575. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6576. --*/
  6577. {
  6578. HTTP2TrafficType SendType;
  6579. #if DBG
  6580. TrafficSentOnChannel = TRUE;
  6581. #endif // DBG
  6582. SendType = SendContext->TrafficType;
  6583. ASSERT((SendType == http2ttData)
  6584. || (SendType == http2ttRTS)
  6585. || (SendType == http2ttRaw) );
  6586. // if the plug level says this packet should not go through, queue it
  6587. // This means the traffic is no raw, and the plug level is less than
  6588. // the send type. Since the constants are ordered this comparison is
  6589. // sufficient
  6590. if ((SendType != http2ttRaw) && (PlugLevel <= SendType))
  6591. {
  6592. SendContext->SetListEntryUsed();
  6593. Mutex.Request();
  6594. // queue and exit
  6595. if (SendContext->Flags & SendContextFlagPutInFront)
  6596. {
  6597. RpcpfInsertHeadList(&BufferQueueHead, &SendContext->ListEntry);
  6598. }
  6599. else
  6600. {
  6601. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  6602. }
  6603. Mutex.Clear();
  6604. return RPC_S_OK;
  6605. }
  6606. else
  6607. {
  6608. // can't put in front on unplugged channel
  6609. ASSERT((SendContext->Flags & SendContextFlagPutInFront) == 0);
  6610. return HTTP2TransportChannel::Send(SendContext);
  6611. }
  6612. }
  6613. void HTTP2PlugChannel::Abort (
  6614. IN RPC_STATUS RpcStatus
  6615. )
  6616. /*++
  6617. Routine Description:
  6618. Abort the channel
  6619. Arguments:
  6620. RpcStatus - the error code with which we abort
  6621. Return Value:
  6622. Note: All sends carry a refcount. We must fully complete the sends
  6623. --*/
  6624. {
  6625. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PLUG_CHANNEL, RpcStatus);
  6626. HTTP2TransportChannel::Abort(RpcStatus);
  6627. SendFailedStatus = RpcStatus;
  6628. // Abort is made from submission context. We
  6629. // know it is synchronized with other submissions
  6630. // and we cannot issue upcalls for it. We will just post
  6631. // as many direct send completions as there are buffers in
  6632. // the queue. When the post comes around, it will dequeue
  6633. // and free one buffer for every post.
  6634. // We know that after abort there will be no more submissions,
  6635. // so not dequeuing them is fine
  6636. if (BufferQueueHead.Flink != &BufferQueueHead)
  6637. {
  6638. (void) COMMON_PostRuntimeEvent(PLUG_CHANNEL_DIRECT_SEND,
  6639. this
  6640. );
  6641. }
  6642. }
  6643. void HTTP2PlugChannel::FreeObject (
  6644. void
  6645. )
  6646. /*++
  6647. Routine Description:
  6648. Frees the object. Acts like a destructor for the
  6649. channel.
  6650. Arguments:
  6651. Return Value:
  6652. --*/
  6653. {
  6654. if (LowerLayer)
  6655. LowerLayer->FreeObject();
  6656. HTTP2PlugChannel::~HTTP2PlugChannel();
  6657. }
  6658. void HTTP2PlugChannel::Reset (
  6659. void
  6660. )
  6661. /*++
  6662. Routine Description:
  6663. Reset the channel for next open/send/receive. This is
  6664. used in submission context only and implies there are no
  6665. pending operations on the channel. It is used on the client
  6666. during opening the connection to do quick negotiation on the
  6667. same connection instead of opening a new connection every time.
  6668. Arguments:
  6669. Return Value:
  6670. --*/
  6671. {
  6672. ASSERT(SendFailedStatus);
  6673. ASSERT(RpcpIsListEmpty(&BufferQueueHead));
  6674. PlugLevel = http2plDataPlugged;
  6675. LowerLayer->Reset();
  6676. }
  6677. RPC_STATUS HTTP2PlugChannel::DirectSendComplete (
  6678. void
  6679. )
  6680. /*++
  6681. Routine Description:
  6682. Direct send complete notification. Complete the send
  6683. passing it only through channels that have seen it (i.e.
  6684. above us)
  6685. Arguments:
  6686. Return Value:
  6687. RPC_S_OK
  6688. --*/
  6689. {
  6690. HTTP2SendContext *QueuedSendContext;
  6691. LIST_ENTRY *QueuedListEntry;
  6692. LIST_ENTRY *NextListEntry;
  6693. RPC_STATUS RpcStatus;
  6694. ASSERT(SendFailedStatus != RPC_S_INTERNAL_ERROR);
  6695. QueuedListEntry = BufferQueueHead.Flink;
  6696. // we wouldn't have a post if there wasn't something
  6697. // in the list.
  6698. ASSERT(QueuedListEntry != &BufferQueueHead);
  6699. do
  6700. {
  6701. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  6702. // capture the next field before we issue send complete
  6703. NextListEntry = QueuedListEntry->Flink;
  6704. RpcStatus = HTTP2TransportChannel::SendComplete(SendFailedStatus, QueuedSendContext);
  6705. QueuedListEntry = NextListEntry;
  6706. // we don't care about the return code.
  6707. (void) AsyncCompleteHelper(RpcStatus);
  6708. }
  6709. while (QueuedListEntry != &BufferQueueHead);
  6710. return RPC_S_OK;
  6711. }
  6712. RPC_STATUS HTTP2PlugChannel::Unplug (
  6713. void
  6714. )
  6715. /*++
  6716. Routine Description:
  6717. Unplugs the channel. This means that all bottled up traffic
  6718. starts flowing forward.
  6719. Arguments:
  6720. Return Value:
  6721. RPC_S_OK or RPC_S_* errors
  6722. --*/
  6723. {
  6724. HTTP2SendContext *QueuedSendContext;
  6725. LIST_ENTRY *QueuedListEntry;
  6726. RPC_STATUS RpcStatus;
  6727. // first, send pending traffic. Then open the channel. Otherwise
  6728. // traffic may get out of order
  6729. while (TRUE)
  6730. {
  6731. Mutex.Request();
  6732. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  6733. // if we had non-zero elements ...
  6734. if (QueuedListEntry != &BufferQueueHead)
  6735. {
  6736. Mutex.Clear();
  6737. }
  6738. else
  6739. {
  6740. // we have zero elements - just unplug the channel
  6741. PlugLevel = http2plUnplugged;
  6742. Mutex.Clear();
  6743. RpcStatus = RPC_S_OK;
  6744. break;
  6745. }
  6746. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  6747. QueuedSendContext->SetListEntryUnused();
  6748. // get into submission context - rule 9.
  6749. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  6750. if (RpcStatus == RPC_S_OK)
  6751. {
  6752. RpcStatus = HTTP2TransportChannel::Send(QueuedSendContext);
  6753. TopChannel->FinishSubmitAsync();
  6754. }
  6755. if (RpcStatus != RPC_S_OK)
  6756. {
  6757. QueuedSendContext->SetListEntryUsed();
  6758. Mutex.Request();
  6759. RpcpfInsertHeadList(&BufferQueueHead, QueuedListEntry);
  6760. Mutex.Clear();
  6761. break;
  6762. }
  6763. }
  6764. return RpcStatus;
  6765. }
  6766. void HTTP2PlugChannel::SetStrongPlug (
  6767. void
  6768. )
  6769. /*++
  6770. Routine Description:
  6771. Upgrades the default plug level (http2plDataPlugged) to
  6772. RTS (http2plRTSPlugged)
  6773. Arguments:
  6774. Return Value:
  6775. --*/
  6776. {
  6777. // make sure we haven't done any sending on the channel. The
  6778. // channel cannot change plug levels after the first send
  6779. ASSERT(TrafficSentOnChannel == FALSE);
  6780. PlugLevel = http2plRTSPlugged;
  6781. }
  6782. /*********************************************************************
  6783. HTTP2ProxyPlugChannel
  6784. *********************************************************************/
  6785. RPC_STATUS HTTP2ProxyPlugChannel::AsyncCompleteHelper (
  6786. IN RPC_STATUS CurrentStatus
  6787. )
  6788. /*++
  6789. Routine Description:
  6790. A helper function that completes an async io.
  6791. Arguments:
  6792. CurrentStatus - the status with which the complete
  6793. notification completed.
  6794. Return Value:
  6795. --*/
  6796. {
  6797. return ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  6798. }
  6799. /*********************************************************************
  6800. HTTP2FlowControlSender
  6801. *********************************************************************/
  6802. RPC_STATUS HTTP2FlowControlSender::Send (
  6803. IN OUT HTTP2SendContext *SendContext
  6804. )
  6805. /*++
  6806. Routine Description:
  6807. Send request
  6808. Arguments:
  6809. SendContext - the send context
  6810. Return Value:
  6811. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6812. if SendContextFlagSendLast is set, the following semantics applies:
  6813. RPC_S_OK - no sends are pending. Last context directly sent
  6814. ERROR_IO_PENDING - sends were pending. When they are all drained
  6815. top channel and virtual connection will be notified through
  6816. the LastPacketSentNotification mechanism
  6817. RPC_S_* errors occured during synchronous send
  6818. --*/
  6819. {
  6820. RPC_STATUS RpcStatus;
  6821. HTTP2SendContext *LocalSendContext;
  6822. if (SendContext->TrafficType == http2ttData)
  6823. {
  6824. // we can't send data without knowing the receive window
  6825. // of the peer
  6826. ASSERT(PeerReceiveWindow != 0);
  6827. }
  6828. if (SendContext->Flags & SendContextFlagSendLast)
  6829. {
  6830. // register the last send. We know if this is called, no
  6831. // new sends will be submitted. However, we race with the
  6832. // send complete thread
  6833. InterlockedExchangePointer((PVOID *)&SendContextOnDrain, SendContext);
  6834. if (SendsPending.GetInteger() == 0)
  6835. {
  6836. // no sends are pending. Attempt to grab back the context
  6837. // and do it synchronously
  6838. LocalSendContext =
  6839. (HTTP2SendContext *)InterlockedExchangePointer((PVOID *)&SendContextOnDrain, NULL);
  6840. if (LocalSendContext)
  6841. {
  6842. // we managed to grab it back. We have won the right to
  6843. // synchronously submit the last context.
  6844. RpcStatus = HTTP2TransportChannel::Send(LocalSendContext);
  6845. // return ok or an error
  6846. return RpcStatus;
  6847. }
  6848. }
  6849. // either there are sends pending, or we lost the race and we have to
  6850. // rely on asynchronous notifications
  6851. return ERROR_IO_PENDING;
  6852. }
  6853. SendsPending.Increment();
  6854. return SendInternal(SendContext,
  6855. FALSE // IgnoreQueuedPackets
  6856. );
  6857. }
  6858. RPC_STATUS HTTP2FlowControlSender::SendComplete (
  6859. IN RPC_STATUS EventStatus,
  6860. IN OUT HTTP2SendContext *SendContext
  6861. )
  6862. /*++
  6863. Routine Description:
  6864. Send complete notification
  6865. Arguments:
  6866. EventStatus - the status of the send
  6867. SendContext - send context
  6868. Return Value:
  6869. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6870. --*/
  6871. {
  6872. RPC_STATUS RpcStatus;
  6873. RPC_STATUS RpcStatus2;
  6874. int LocalSendsPending;
  6875. HTTP2SendContext *LocalSendContextOnDrain;
  6876. LocalSendsPending = SendsPending.Decrement();
  6877. // in the case of Last packet to send completing, the counter will wrap to -1 here because
  6878. // the last send is not present in SendsPending. That's ok.
  6879. RpcStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  6880. if (LocalSendsPending == 0)
  6881. {
  6882. LocalSendContextOnDrain = (HTTP2SendContext *) SendContextOnDrain;
  6883. if (LocalSendContextOnDrain)
  6884. {
  6885. // try to consume the SendContextOnDrain in a thread safe manner
  6886. // in respect to a thread that is setting it. In the cases where SendContextOnDrain
  6887. // will be called the channel is already detached, so we know no new sends will
  6888. // be submitted and we don't need to worry about the race with SendsPending going
  6889. // up again
  6890. LocalSendContextOnDrain =
  6891. (HTTP2SendContext *)InterlockedCompareExchangePointer((PVOID *)&SendContextOnDrain,
  6892. NULL,
  6893. LocalSendContextOnDrain
  6894. );
  6895. if (LocalSendContextOnDrain)
  6896. {
  6897. // remove the reference for the previous send
  6898. TopChannel->RemoveReference();
  6899. // last packet must be RTS.
  6900. ASSERT(LocalSendContextOnDrain->TrafficType == http2ttRTS);
  6901. RpcStatus = TopChannel->LastPacketSentNotification(LocalSendContextOnDrain);
  6902. // don't care about return code. This channel is dying anyway
  6903. RpcStatus2 = TopChannel->Send(LocalSendContextOnDrain);
  6904. // the second error takes precedence here
  6905. if (RpcStatus2 != RPC_S_OK)
  6906. RpcStatus = RpcStatus2;
  6907. }
  6908. }
  6909. }
  6910. return RpcStatus;
  6911. }
  6912. void HTTP2FlowControlSender::Abort (
  6913. IN RPC_STATUS RpcStatus
  6914. )
  6915. /*++
  6916. Routine Description:
  6917. Abort the channel
  6918. Arguments:
  6919. RpcStatus - the error code with which we abort
  6920. Return Value:
  6921. --*/
  6922. {
  6923. // we have a bunch of sends carrying ref-counts, etc.
  6924. // We must make sure they are completed.
  6925. HTTP2TransportChannel::Abort(RpcStatus);
  6926. // we know we are synchronized with everybody else
  6927. if (!RpcpIsListEmpty(&BufferQueueHead))
  6928. {
  6929. AbortStatus = RpcStatus;
  6930. (void) COMMON_PostRuntimeEvent(HTTP2_FLOW_CONTROL_DIRECT_SEND,
  6931. this
  6932. );
  6933. }
  6934. }
  6935. void HTTP2FlowControlSender::FreeObject (
  6936. void
  6937. )
  6938. /*++
  6939. Routine Description:
  6940. Frees the object. Acts like a destructor for the
  6941. channel.
  6942. Arguments:
  6943. Return Value:
  6944. --*/
  6945. {
  6946. if (LowerLayer)
  6947. LowerLayer->FreeObject();
  6948. HTTP2FlowControlSender::~HTTP2FlowControlSender();
  6949. }
  6950. void HTTP2FlowControlSender::SendCancelled (
  6951. IN HTTP2SendContext *SendContext
  6952. )
  6953. /*++
  6954. Routine Description:
  6955. A lower channel cancelled a send already passed through this channel.
  6956. Arguments:
  6957. SendContext - the send context of the send that was cancelled
  6958. Return Value:
  6959. Note:
  6960. The channel must not be receiving new requests by now (i.e.
  6961. it must be non-default and fully drained)
  6962. --*/
  6963. {
  6964. SendsPending.Decrement();
  6965. UpperLayer->SendCancelled(SendContext);
  6966. }
  6967. RPC_STATUS HTTP2FlowControlSender::FlowControlAckNotify (
  6968. IN ULONG BytesReceivedForAck,
  6969. IN ULONG WindowForAck
  6970. )
  6971. /*++
  6972. Routine Description:
  6973. Notifies the channel that a flow control ack has arrived.
  6974. Arguments:
  6975. BytesReceivedForAck - the bytes received from the ack packet
  6976. WindowForAck - the available window advertised in the ack
  6977. Return Value:
  6978. RPC_S_OK or RPC_S_PROTOCOL_ERROR if the received values are bogus
  6979. --*/
  6980. {
  6981. LIST_ENTRY *CurrentListEntry;
  6982. LIST_ENTRY *NextListEntry;
  6983. HTTP2SendContext *SendContext;
  6984. RPC_STATUS RpcStatus;
  6985. BOOL ChannelNeedsRecycling;
  6986. #if 0
  6987. DbgPrint("%X: Flow control ack notify received: %d; %d\n",
  6988. GetCurrentProcessId(),
  6989. BytesReceivedForAck,
  6990. WindowForAck
  6991. );
  6992. #endif
  6993. RpcStatus = RPC_S_OK;
  6994. ChannelNeedsRecycling = FALSE;
  6995. Mutex.Request();
  6996. ASSERT((DataBytesSent - BytesReceivedForAck) <= PeerReceiveWindow);
  6997. if ((DataBytesSent - BytesReceivedForAck) > PeerReceiveWindow)
  6998. {
  6999. Mutex.Clear();
  7000. return RPC_S_PROTOCOL_ERROR;
  7001. }
  7002. PeerAvailableWindow = WindowForAck - (DataBytesSent - BytesReceivedForAck);
  7003. ASSERT(PeerAvailableWindow <= PeerReceiveWindow);
  7004. if (PeerAvailableWindow > PeerReceiveWindow)
  7005. {
  7006. Mutex.Clear();
  7007. return RPC_S_PROTOCOL_ERROR;
  7008. }
  7009. // did we free up enough window to send some of our queued buffers?
  7010. CurrentListEntry = BufferQueueHead.Flink;
  7011. while (CurrentListEntry != &BufferQueueHead)
  7012. {
  7013. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7014. if (SendContext->maxWriteBuffer <= PeerAvailableWindow)
  7015. {
  7016. SendContext->SetListEntryUnused();
  7017. RpcpfRemoveHeadList(&BufferQueueHead);
  7018. // set the CurrentListEntry for the next iteration of the loop
  7019. CurrentListEntry = BufferQueueHead.Flink;
  7020. // send it through this channel. This will update DataBytesSent
  7021. // and PeerAvailableWindow
  7022. RpcStatus = SendInternal(SendContext,
  7023. TRUE // IgnoreQueuedPackets
  7024. );
  7025. if (RpcStatus != RPC_S_OK)
  7026. {
  7027. if (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING)
  7028. {
  7029. // we failed to send - stick back the current context and
  7030. // return error. This will cause caller to abort and
  7031. // this will complete all queued sends
  7032. SendContext->SetListEntryUsed();
  7033. RpcpfInsertHeadList(&BufferQueueHead, &SendContext->ListEntry);
  7034. break;
  7035. }
  7036. else
  7037. {
  7038. // remeber that we need to return RPC_P_CHANNEL_NEEDS_RECYCLING at
  7039. // the end
  7040. ChannelNeedsRecycling = TRUE;
  7041. }
  7042. }
  7043. }
  7044. else
  7045. {
  7046. // we don't have enough space to send more. Break out of the loop
  7047. break;
  7048. }
  7049. }
  7050. Mutex.Clear();
  7051. if (ChannelNeedsRecycling)
  7052. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  7053. else
  7054. return RpcStatus;
  7055. }
  7056. void HTTP2FlowControlSender::GetBufferQueue (
  7057. OUT LIST_ENTRY *NewQueueHead
  7058. )
  7059. /*++
  7060. Routine Description:
  7061. Grab all queued buffers and pile them on the list head
  7062. that we passed to it. All refcounts must be removed (i.e.
  7063. undone).
  7064. Arguments:
  7065. NewQueueHead - new queue heads to pile buffers on
  7066. Return Value:
  7067. --*/
  7068. {
  7069. LIST_ENTRY *CurrentListEntry;
  7070. LIST_ENTRY *NextListEntry;
  7071. HTTP2SendContext *SendContext;
  7072. ASSERT(RpcpIsListEmpty(NewQueueHead));
  7073. Mutex.Request();
  7074. CurrentListEntry = BufferQueueHead.Flink;
  7075. while (CurrentListEntry != &BufferQueueHead)
  7076. {
  7077. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7078. SendContext->SetListEntryUnused();
  7079. NextListEntry = CurrentListEntry->Flink;
  7080. RpcpfInsertHeadList(NewQueueHead, CurrentListEntry);
  7081. UpperLayer->SendCancelled(SendContext);
  7082. CurrentListEntry = NextListEntry;
  7083. }
  7084. RpcpInitializeListHead(&BufferQueueHead);
  7085. Mutex.Clear();
  7086. }
  7087. RPC_STATUS HTTP2FlowControlSender::DirectSendComplete (
  7088. OUT BOOL *IsServer,
  7089. OUT BOOL *SendToRuntime,
  7090. OUT void **SendContext,
  7091. OUT BUFFER *Buffer,
  7092. OUT UINT *BufferLength
  7093. )
  7094. /*++
  7095. Routine Description:
  7096. Direct send complete notification. Complete the send
  7097. passing it only through channels that have seen it (i.e.
  7098. above us). Note that we will get one notification for
  7099. all buffered sends. We must empty the whole queue, and post
  7100. one notification for each buffer in the queue
  7101. Arguments:
  7102. IsServer - in all cases MUST be set to TRUE or FALSE.
  7103. SendToRuntime - in all cases MUST be set to TRUE or FALSE. If FALSE,
  7104. it won't be sent to the runtime (used by proxies)
  7105. SendContext - on output contains the send context as
  7106. seen by the runtime
  7107. Buffer - on output the buffer that we tried to send
  7108. BufferLength - on output the length of the buffer we tried to send
  7109. Return Value:
  7110. RPC_S_OK to return error to runtime
  7111. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  7112. RPC_S_* error - return error to runtime
  7113. --*/
  7114. {
  7115. LIST_ENTRY *CurrentListEntry;
  7116. HTTP2SendContext *CurrentSendContext;
  7117. RPC_STATUS RpcStatus;
  7118. BOOL PostAnotherReceive;
  7119. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_FLOW_CONTROL_SENDER,
  7120. !RpcpIsListEmpty(&BufferQueueHead));
  7121. *IsServer = (BOOL)(this->IsServer);
  7122. *SendToRuntime = (BOOL)(this->SendToRuntime);
  7123. // this should only get called when we are aborted. This
  7124. // ensures that we are single threaded in the code
  7125. // below
  7126. TopChannel->VerifyAborted();
  7127. CurrentListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  7128. ASSERT(CurrentListEntry != &BufferQueueHead);
  7129. CurrentSendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7130. CurrentSendContext->SetListEntryUnused();
  7131. ASSERT(AbortStatus != RPC_S_OK);
  7132. RpcStatus = HTTP2TransportChannel::SendComplete(AbortStatus, CurrentSendContext);
  7133. PostAnotherReceive = !(RpcpIsListEmpty(&BufferQueueHead));
  7134. if ((RpcStatus != RPC_P_PACKET_CONSUMED) && this->SendToRuntime)
  7135. {
  7136. // this will return to the runtime. Make sure it is valid
  7137. if (this->IsServer)
  7138. I_RpcTransVerifyServerRuntimeCallFromContext(CurrentSendContext);
  7139. else
  7140. I_RpcTransVerifyClientRuntimeCallFromContext(CurrentSendContext);
  7141. *SendContext = CurrentSendContext;
  7142. *Buffer = CurrentSendContext->pWriteBuffer;
  7143. *BufferLength = CurrentSendContext->maxWriteBuffer;
  7144. }
  7145. else
  7146. {
  7147. // the packet was a transport packet - it won't be seen by the runtime
  7148. *SendContext = NULL;
  7149. *Buffer = NULL;
  7150. *BufferLength = 0;
  7151. }
  7152. RpcStatus = AsyncCompleteHelper(RpcStatus);
  7153. // do not touch this pointer after here unless the list was not-empty
  7154. // (which implies we still have refcounts)
  7155. if (PostAnotherReceive)
  7156. {
  7157. (void) COMMON_PostRuntimeEvent(HTTP2_FLOW_CONTROL_DIRECT_SEND,
  7158. this
  7159. );
  7160. }
  7161. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_FLOW_CONTROL_SENDER,
  7162. PostAnotherReceive);
  7163. return RpcStatus;
  7164. }
  7165. RPC_STATUS HTTP2FlowControlSender::SendInternal (
  7166. IN OUT HTTP2SendContext *SendContext,
  7167. IN BOOL IgnoreQueuedBuffers
  7168. )
  7169. /*++
  7170. Routine Description:
  7171. Send request without incrementing SendsPending counter
  7172. and without handling SendContextFlagSendLast
  7173. Arguments:
  7174. SendContext - the send context
  7175. IgnoreQueuedBuffers - if non-zero, the send will proceed even if
  7176. there are queued buffers. If FALSE, the send will be queued
  7177. if there are queued buffers.
  7178. Return Value:
  7179. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7180. --*/
  7181. {
  7182. RPC_STATUS RpcStatus;
  7183. HTTP2SendContext *LocalSendContext;
  7184. if (SendContext->TrafficType == http2ttData)
  7185. {
  7186. Mutex.Request();
  7187. // if the peer doesn't have enough window to accept this packet
  7188. // or there are queued packets and we were told not to ignore them,
  7189. // we have to queue it. Otherwise we can send it
  7190. if (
  7191. (PeerAvailableWindow < SendContext->maxWriteBuffer)
  7192. ||
  7193. (
  7194. (IgnoreQueuedBuffers == FALSE)
  7195. &&
  7196. (BufferQueueHead.Flink != &BufferQueueHead)
  7197. )
  7198. )
  7199. {
  7200. // either the receiver doesn't have enough window or
  7201. // we have pending buffers
  7202. SendContext->SetListEntryUsed();
  7203. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  7204. Mutex.Clear();
  7205. #if DBG_ERROR
  7206. DbgPrint("Flow controlling sends ...%p\n", this);
  7207. #endif
  7208. return RPC_S_OK;
  7209. }
  7210. else
  7211. {
  7212. // yes, update counters and continue with send
  7213. DataBytesSent += SendContext->maxWriteBuffer;
  7214. PeerAvailableWindow -= SendContext->maxWriteBuffer;
  7215. }
  7216. Mutex.Clear();
  7217. }
  7218. return HTTP2TransportChannel::Send(SendContext);
  7219. }
  7220. /*********************************************************************
  7221. HTTP2PingOriginator
  7222. *********************************************************************/
  7223. RPC_STATUS HTTP2PingOriginator::Send (
  7224. IN OUT HTTP2SendContext *SendContext
  7225. )
  7226. /*++
  7227. Routine Description:
  7228. Send request
  7229. Arguments:
  7230. SendContext - the send context
  7231. Return Value:
  7232. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7233. --*/
  7234. {
  7235. ConsecutivePingsOnInterval = 0;
  7236. return SendInternal(SendContext);
  7237. }
  7238. RPC_STATUS HTTP2PingOriginator::SendComplete (
  7239. IN RPC_STATUS EventStatus,
  7240. IN OUT HTTP2SendContext *SendContext
  7241. )
  7242. /*++
  7243. Routine Description:
  7244. Send complete notification. Consume packets generated by us
  7245. and forward everything else up.
  7246. Arguments:
  7247. EventStatus - the status of the send
  7248. SendContext - send context
  7249. Return Value:
  7250. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7251. --*/
  7252. {
  7253. if ((SendContext->TrafficType == http2ttRTS)
  7254. && (TrustedIsPingPacket(SendContext->pWriteBuffer)))
  7255. {
  7256. // this is a packet we generated. Eat it up
  7257. FreeRTSPacket(SendContext);
  7258. return RPC_P_PACKET_CONSUMED;
  7259. }
  7260. return HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  7261. }
  7262. RPC_STATUS HTTP2PingOriginator::SetKeepAliveTimeout (
  7263. IN BOOL TurnOn,
  7264. IN BOOL bProtectIO,
  7265. IN KEEPALIVE_TIMEOUT_UNITS Units,
  7266. IN OUT KEEPALIVE_TIMEOUT KATime,
  7267. IN ULONG KAInterval OPTIONAL
  7268. )
  7269. /*++
  7270. Routine Description:
  7271. Change the keep alive value on the channel
  7272. Arguments:
  7273. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  7274. are turned off.
  7275. bProtectIO - non-zero if IO needs to be protected against async close
  7276. of the connection. Ignored for this function since we are always
  7277. protected when we start a new submit.
  7278. Units - in what units is KATime
  7279. KATime - how much to wait before turning on keep alives. Ignored in this
  7280. function.
  7281. KAInterval - the interval between keep alives
  7282. Return Value:
  7283. RPC_S_OK or other RPC_S_* errors for error
  7284. --*/
  7285. {
  7286. RPC_STATUS RpcStatus;
  7287. ULONG LocalNewPingInterval;
  7288. // technically the time stamp can be 0, but this would
  7289. // be extremely rare
  7290. ASSERT(LastPacketSentTimestamp);
  7291. ASSERT(Units == tuMilliseconds);
  7292. if (TurnOn == FALSE)
  7293. KeepAliveInterval = 0;
  7294. else
  7295. KeepAliveInterval = KAInterval;
  7296. LocalNewPingInterval = GetPingInterval(ConnectionTimeout,
  7297. KeepAliveInterval
  7298. );
  7299. return SetNewPingInterval(LocalNewPingInterval);
  7300. }
  7301. void HTTP2PingOriginator::Abort (
  7302. IN RPC_STATUS RpcStatus
  7303. )
  7304. /*++
  7305. Routine Description:
  7306. Abort the channel
  7307. Arguments:
  7308. RpcStatus - the error code with which we abort
  7309. Return Value:
  7310. --*/
  7311. {
  7312. HTTP2TransportChannel::Abort(RpcStatus);
  7313. // we are already synchronized with everybody. Just
  7314. // call the internal function
  7315. DisablePingsInternal();
  7316. }
  7317. void HTTP2PingOriginator::FreeObject (
  7318. void
  7319. )
  7320. /*++
  7321. Routine Description:
  7322. Frees the object. Acts like a destructor for the
  7323. channel.
  7324. Arguments:
  7325. Return Value:
  7326. --*/
  7327. {
  7328. if (LowerLayer)
  7329. LowerLayer->FreeObject();
  7330. HTTP2PingOriginator::~HTTP2PingOriginator();
  7331. }
  7332. void HTTP2PingOriginator::SendCancelled (
  7333. IN HTTP2SendContext *SendContext
  7334. )
  7335. /*++
  7336. Routine Description:
  7337. A lower channel cancelled a send already passed through this channel.
  7338. Arguments:
  7339. SendContext - the send context of the send that was cancelled
  7340. Return Value:
  7341. --*/
  7342. {
  7343. RPC_STATUS RpcStatus;
  7344. // a call was cancelled. We don't know what was the last sent
  7345. // time before that, so the only safe thing to do is send another
  7346. // ping. This should be extremely rare as it happens only sometimes
  7347. // during channel recycling.
  7348. RpcStatus = ReferenceFromCallback();
  7349. // if already aborted, don't bother
  7350. if (RpcStatus != RPC_S_OK)
  7351. return;
  7352. // we don't care about the result. The channel is dying. If we
  7353. // managed to submit the ping, it's better. If not, we hope the
  7354. // channel will last for long enough in order to complete the
  7355. // recycle process
  7356. RpcStatus = SendPingPacket();
  7357. // SendCancelled will be called only when the channel is close to the
  7358. // end of its recycling. We cannot get another recycling request here.
  7359. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  7360. TopChannel->FinishSubmitAsync();
  7361. UpperLayer->SendCancelled(SendContext);
  7362. }
  7363. void HTTP2PingOriginator::Reset (
  7364. void
  7365. )
  7366. /*++
  7367. Routine Description:
  7368. Reset the channel for next open/send/receive. This is
  7369. used in submission context only and implies there are no
  7370. pending operations on the channel. It is used on the client
  7371. during opening the connection to do quick negotiation on the
  7372. same connection instead of opening a new connection every time.
  7373. Arguments:
  7374. Return Value:
  7375. --*/
  7376. {
  7377. LastPacketSentTimestamp = 0;
  7378. LowerLayer->Reset();
  7379. }
  7380. RPC_STATUS HTTP2PingOriginator::SetConnectionTimeout (
  7381. IN ULONG ConnectionTimeout
  7382. )
  7383. /*++
  7384. Routine Description:
  7385. Sets the connection timeout for the ping channel. The ping channel
  7386. does not ping when initialized. This call starts the process. It is
  7387. synchronized with DisablePings but not with Aborts.
  7388. Arguments:
  7389. ConnectionTimeout - the connection timeout in milliseconds
  7390. Return Value:
  7391. RPC_S_OK or RPC_S_* error
  7392. --*/
  7393. {
  7394. RPC_STATUS RpcStatus;
  7395. ULONG LocalNewPingInterval;
  7396. // we don't accept anything less than the minimum timeout
  7397. if (ConnectionTimeout <= MinimumConnectionTimeout)
  7398. return RPC_S_PROTOCOL_ERROR;
  7399. // technically the time stamp can be 0, but this would
  7400. // be extremely rare
  7401. ASSERT(LastPacketSentTimestamp);
  7402. if (OverrideMinimumConnectionTimeout)
  7403. this->ConnectionTimeout = min(ConnectionTimeout, OverrideMinimumConnectionTimeout);
  7404. else
  7405. this->ConnectionTimeout = ConnectionTimeout;
  7406. LocalNewPingInterval = GetPingInterval(ConnectionTimeout,
  7407. KeepAliveInterval
  7408. );
  7409. return SetNewPingInterval(LocalNewPingInterval);
  7410. }
  7411. void HTTP2PingOriginator::DisablePings (
  7412. void
  7413. )
  7414. /*++
  7415. Routine Description:
  7416. Disables the pings for the channel. Synchronized with
  7417. SetConnectionTimeout but not with Aborts
  7418. Arguments:
  7419. Return Value:
  7420. RPC_S_OK or RPC_S_* error
  7421. --*/
  7422. {
  7423. RPC_STATUS RpcStatus;
  7424. // synchronize with aborts and then call internal
  7425. // routine
  7426. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  7427. if (RpcStatus == RPC_S_OK)
  7428. {
  7429. DisablePingsInternal();
  7430. TopChannel->FinishSubmitAsync();
  7431. }
  7432. }
  7433. void HTTP2PingOriginator::TimerCallback (
  7434. void
  7435. )
  7436. /*++
  7437. Routine Description:
  7438. Timer callback routine - a periodic timer fired.
  7439. Figure out what type of timer it was, and take
  7440. appropriate action.
  7441. N.B. We enter this routine with BeginSubmitAsync
  7442. called on this channel
  7443. Arguments:
  7444. Return Value:
  7445. --*/
  7446. {
  7447. ULONG CurrentTickCount;
  7448. ULONG LocalLastSentTickCount;
  7449. RPC_STATUS RpcStatus;
  7450. ULONG LocalPingInterval;
  7451. BOOL PingPacketSent;
  7452. LocalLastSentTickCount = LastPacketSentTimestamp;
  7453. CurrentTickCount = NtGetTickCount();
  7454. // if less than the grace period has expired since the last
  7455. // packet was sent, don't bother to send a ping
  7456. if (CurrentTickCount - LocalLastSentTickCount >= GetGracePeriod())
  7457. {
  7458. PingPacketSent = TRUE;
  7459. ConsecutivePingsOnInterval ++;
  7460. #if DBG_ERROR
  7461. DbgPrint("Timer expired. No recent activity - sending ping ...\n");
  7462. #endif
  7463. RpcStatus = SendPingPacket();
  7464. if ((RpcStatus != RPC_S_OK)
  7465. && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  7466. {
  7467. #if DBG_ERROR
  7468. DbgPrint("Ping failed. Aborting connection.\n");
  7469. #endif
  7470. TopChannel->FinishSubmitAsync();
  7471. // offload the aborting to a worker thread (rule 33)
  7472. (void) COMMON_PostRuntimeEvent(HTTP2_ABORT_CONNECTION,
  7473. TopChannel
  7474. );
  7475. return;
  7476. }
  7477. if (ConsecutivePingsOnInterval >= ThresholdConsecutivePingsOnInterval)
  7478. {
  7479. LocalPingInterval = ScaleBackPingInterval();
  7480. if (LocalPingInterval > PingInterval)
  7481. {
  7482. // we need to scale back. We can't do it from the timer callback, so we
  7483. // need to offload to a worker thread for this
  7484. ConsecutivePingsOnInterval = 0;
  7485. // add a reference for the offloaded work item
  7486. TopChannel->AddReference();
  7487. (void) COMMON_PostRuntimeEvent(HTTP2_RESCHEDULE_TIMER,
  7488. this
  7489. );
  7490. }
  7491. }
  7492. }
  7493. else
  7494. {
  7495. PingPacketSent = FALSE;
  7496. #if DBG_ERROR
  7497. DbgPrint("Timer expired. Recent activity on channel detected - no ping necessary\n");
  7498. #endif
  7499. }
  7500. TopChannel->FinishSubmitAsync();
  7501. if ((PingPacketSent != FALSE) && (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING))
  7502. {
  7503. // we have the timer callback reference here which protects us. Once we
  7504. // offload to a worker thread, the reference doesn't hold. Add another
  7505. // reference for this.
  7506. TopChannel->AddReference();
  7507. // offload the recycling to a worker thread. This is necessary because
  7508. // the recycling will abort on failure which violates rule 33.
  7509. (void) COMMON_PostRuntimeEvent(HTTP2_RECYCLE_CHANNEL,
  7510. TopChannel
  7511. );
  7512. }
  7513. }
  7514. RPC_STATUS HTTP2PingOriginator::ReferenceFromCallback (
  7515. void
  7516. )
  7517. /*++
  7518. Routine Description:
  7519. References a ping originator object from the callback
  7520. routine.
  7521. Arguments:
  7522. Return Value:
  7523. RPC_S_OK or RPC_S_* error
  7524. --*/
  7525. {
  7526. return TopChannel->BeginSubmitAsync();
  7527. }
  7528. RPC_STATUS HTTP2PingOriginator::SetNewPingInterval (
  7529. IN ULONG NewPingInterval
  7530. )
  7531. /*++
  7532. Routine Description:
  7533. Puts into effect the new ping interval. This means
  7534. cancelling the old interval (if any) and setting
  7535. the timer for the new. Must NOT be called from
  7536. timer callbacks or we will deadlock.
  7537. Arguments:
  7538. NewPingInterval - the new ping interval to use
  7539. Return Value:
  7540. RPC_S_OK or RPC_S_* error
  7541. --*/
  7542. {
  7543. RPC_STATUS RpcStatus;
  7544. BOOL Result;
  7545. // the new interval is different than the old. Need to update
  7546. // and reschedule
  7547. PingInterval = NewPingInterval;
  7548. ConsecutivePingsOnInterval = 0;
  7549. // synchronize with Aborts
  7550. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  7551. if (RpcStatus != RPC_S_OK)
  7552. return RpcStatus;
  7553. if (PingTimer)
  7554. {
  7555. DisablePingsInternal();
  7556. }
  7557. Result = CreateTimerQueueTimer(&PingTimer,
  7558. NULL,
  7559. HTTP2TimerCallback,
  7560. this,
  7561. PingInterval, // time to first fire
  7562. PingInterval, // periodic interval
  7563. WT_EXECUTELONGFUNCTION
  7564. );
  7565. if (Result == FALSE)
  7566. {
  7567. PingTimer = NULL;
  7568. TopChannel->FinishSubmitAsync();
  7569. return RPC_S_OUT_OF_MEMORY;
  7570. }
  7571. // add one reference for the timer callback we have set up
  7572. TopChannel->AddReference();
  7573. TopChannel->FinishSubmitAsync();
  7574. return RPC_S_OK;
  7575. }
  7576. void HTTP2PingOriginator::RescheduleTimer (
  7577. void
  7578. )
  7579. /*++
  7580. Routine Description:
  7581. Reschedules a timer. This means scale back a timer.
  7582. Arguments:
  7583. Return Value:
  7584. --*/
  7585. {
  7586. ULONG LocalPingInterval;
  7587. LocalPingInterval = ScaleBackPingInterval();
  7588. if (LocalPingInterval > PingInterval)
  7589. {
  7590. // ignore the result. Scaling back is a best effort.
  7591. // If it fails, that's ok.
  7592. (void) SetNewPingInterval(LocalPingInterval);
  7593. }
  7594. // remove the reference for the work item
  7595. TopChannel->RemoveReference();
  7596. }
  7597. void HTTP2PingOriginator::DisablePingsInternal (
  7598. void
  7599. )
  7600. /*++
  7601. Routine Description:
  7602. Disables the pings for the channel. Must be synchronized with
  7603. SetConnectionTimeout, Abort and DisablePings
  7604. Arguments:
  7605. Return Value:
  7606. RPC_S_OK or RPC_S_* error
  7607. --*/
  7608. {
  7609. BOOL Result;
  7610. if (PingTimer)
  7611. {
  7612. Result = DeleteTimerQueueTimer(NULL,
  7613. PingTimer,
  7614. INVALID_HANDLE_VALUE // tell the timer function to wait for all callbacks
  7615. // to complete before returning
  7616. );
  7617. #if DBG
  7618. // during process shutdown the loader termination code will
  7619. // shutdown threads (including the NTDLL thread pool threads)
  7620. // before it indicates to anybody that it is doing so. This ASSERT
  7621. // will fire in such cases causing random stress breaks. Disable it.
  7622. // ASSERT(Result);
  7623. #endif // DBG
  7624. // we added one reference for the timer callback. Remove it
  7625. TopChannel->RemoveReference();
  7626. PingTimer = NULL;
  7627. }
  7628. }
  7629. RPC_STATUS HTTP2PingOriginator::SendPingPacket (
  7630. void
  7631. )
  7632. /*++
  7633. Routine Description:
  7634. Sends a ping packet on this channel. Must be called with AsyncSubmit
  7635. started.
  7636. Arguments:
  7637. Return Value:
  7638. RPC_S_OK or RPC_S_* error
  7639. --*/
  7640. {
  7641. RPC_STATUS RpcStatus;
  7642. HTTP2SendContext *PingPacket;
  7643. ULONG PingPacketSize;
  7644. PingPacket = AllocateAndInitializePingPacket();
  7645. if (PingPacket == NULL)
  7646. return RPC_S_OUT_OF_MEMORY;
  7647. PingPacketSize = PingPacket->maxWriteBuffer;
  7648. RpcStatus = SendInternal(PingPacket);
  7649. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  7650. FreeRTSPacket(PingPacket);
  7651. else if (NotifyTopChannelForPings)
  7652. TopChannel->PingTrafficSentNotify(PingPacketSize);
  7653. return RpcStatus;
  7654. }
  7655. RPC_STATUS HTTP2PingOriginator::SendInternal (
  7656. IN OUT HTTP2SendContext *SendContext
  7657. )
  7658. /*++
  7659. Routine Description:
  7660. Send request
  7661. Arguments:
  7662. SendContext - the send context
  7663. Return Value:
  7664. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7665. --*/
  7666. {
  7667. LastPacketSentTimestamp = NtGetTickCount();
  7668. return HTTP2TransportChannel::Send(SendContext);
  7669. }
  7670. /*********************************************************************
  7671. HTTP2PingReceiver
  7672. *********************************************************************/
  7673. RPC_STATUS HTTP2PingReceiver::ReceiveComplete (
  7674. IN RPC_STATUS EventStatus,
  7675. IN HTTP2TrafficType TrafficType,
  7676. IN BYTE *Buffer,
  7677. IN UINT BufferLength
  7678. )
  7679. /*++
  7680. Routine Description:
  7681. Receive complete notification.
  7682. Arguments:
  7683. EventStatus - status of the operation
  7684. TrafficType - the type of traffic we have received
  7685. Buffer - the received buffer (success only)
  7686. BufferLength - the length of the received buffer (success only)
  7687. Return Value:
  7688. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7689. --*/
  7690. {
  7691. if (EventStatus == RPC_S_OK)
  7692. {
  7693. if (IsRTSPacket(Buffer) && UntrustedIsPingPacket(Buffer, BufferLength))
  7694. {
  7695. // this is a ping packet. Consume it and post another receive if
  7696. // necessary
  7697. if (PostAnotherReceive)
  7698. {
  7699. EventStatus = TopChannel->BeginSubmitAsync();
  7700. if (EventStatus == RPC_S_OK)
  7701. {
  7702. EventStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  7703. TopChannel->FinishSubmitAsync();
  7704. if (EventStatus != RPC_S_OK)
  7705. TopChannel->RemoveReference();
  7706. }
  7707. }
  7708. if (EventStatus == RPC_S_OK)
  7709. {
  7710. // we free the buffer only in success case. In failure case
  7711. // we need a buffer to pass to receive complete down.
  7712. RpcFreeBuffer(Buffer);
  7713. return RPC_P_PACKET_CONSUMED;
  7714. }
  7715. else
  7716. {
  7717. // fall through to indicating a receive failure below
  7718. }
  7719. }
  7720. }
  7721. return HTTP2TransportChannel::ReceiveComplete(EventStatus, TrafficType, Buffer, BufferLength);
  7722. }
  7723. void HTTP2PingReceiver::FreeObject (
  7724. void
  7725. )
  7726. /*++
  7727. Routine Description:
  7728. Frees the object. Acts like a destructor for the
  7729. channel.
  7730. Arguments:
  7731. Return Value:
  7732. --*/
  7733. {
  7734. if (LowerLayer)
  7735. LowerLayer->FreeObject();
  7736. HTTP2PingReceiver::~HTTP2PingReceiver();
  7737. }
  7738. /*********************************************************************
  7739. HTTP2ChannelDataOriginator
  7740. *********************************************************************/
  7741. HTTP2ChannelDataOriginator::HTTP2ChannelDataOriginator (
  7742. IN ULONG ChannelLifetime,
  7743. IN BOOL IsServer,
  7744. OUT RPC_STATUS *Status
  7745. ) : Mutex(Status,
  7746. FALSE, // pre-allocate semaphore
  7747. 5000 // spin count
  7748. )
  7749. /*++
  7750. Routine Description:
  7751. HTTP2ChannelDataOriginator constructor
  7752. Arguments:
  7753. ChannelLifetime - the lifetime read from the registry
  7754. IsServer - non-zero if this is a server side data originator.
  7755. 0 otherwise.
  7756. Status - on input RPC_S_OK. On output, the result of the constructor.
  7757. Return Value:
  7758. --*/
  7759. {
  7760. RpcpInitializeListHead(&BufferQueueHead);
  7761. this->ChannelLifetime = ChannelLifetime;
  7762. NonreservedLifetime = ChannelLifetime;
  7763. if (IsServer)
  7764. NonreservedLifetime -= ServerReservedChannelLifetime;
  7765. else
  7766. NonreservedLifetime -= ClientReservedChannelLifetime;
  7767. this->IsServer = IsServer;
  7768. BytesSentOnChannel = 0;
  7769. ChannelReplacementTriggered = FALSE;
  7770. AbortStatus = RPC_S_OK;
  7771. #if DBG
  7772. RawDataAlreadySent = FALSE;
  7773. #endif // DBG
  7774. }
  7775. RPC_STATUS HTTP2ChannelDataOriginator::Send (
  7776. IN OUT HTTP2SendContext *SendContext
  7777. )
  7778. /*++
  7779. Routine Description:
  7780. Send request
  7781. Arguments:
  7782. SendContext - the send context
  7783. Return Value:
  7784. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7785. --*/
  7786. {
  7787. ULONG NewBytesSentOnChannel;
  7788. BOOL ChannelReplacementNeeded;
  7789. RPC_STATUS RpcStatus;
  7790. ULONG LocalBytesSentOnChannel;
  7791. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  7792. ChannelReplacementNeeded = FALSE;
  7793. // if this is raw traffic, don't count it
  7794. if (SendContext->TrafficType == http2ttRaw)
  7795. {
  7796. RawDataBeingSent();
  7797. }
  7798. // otherwise, count it only if the traffic is not specifically exempt
  7799. else if ((SendContext->Flags & SendContextFlagNonChannelData) == 0)
  7800. {
  7801. // we don't always take the mutex. We know that the bytes sent will only
  7802. // grow. If we think it is a good time to recycle the channel, the fact that
  7803. // another thread is also sending in a race condition with us makes it even
  7804. // more so. We just need to be careful to properly update the BytesSendOnChannel
  7805. // at the end
  7806. LocalBytesSentOnChannel = BytesSentOnChannel;
  7807. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  7808. if ((NewBytesSentOnChannel > NonreservedLifetime) || ChannelReplacementTriggered)
  7809. {
  7810. Mutex.Request();
  7811. // now that we have the mutex, check again. Sometimes the channel
  7812. // can start sending from 0 again (e.g. out proxy negotiates a new
  7813. // out channel with the client and server is ready to start from 0)
  7814. // This can happen in restart channel, which is also protected by the
  7815. // mutex
  7816. LocalBytesSentOnChannel = BytesSentOnChannel;
  7817. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  7818. if ((NewBytesSentOnChannel > NonreservedLifetime) || ChannelReplacementTriggered)
  7819. {
  7820. if (ChannelReplacementTriggered == FALSE)
  7821. {
  7822. ChannelReplacementNeeded = TRUE;
  7823. ChannelReplacementTriggered = TRUE;
  7824. }
  7825. // if this is data, queue it
  7826. if (SendContext->TrafficType == http2ttData)
  7827. {
  7828. SendContext->SetListEntryUsed();
  7829. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  7830. Mutex.Clear();
  7831. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  7832. if (ChannelReplacementNeeded)
  7833. {
  7834. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHANNEL_RECYCLE, HTTP2LOG_OT_CDATA_ORIGINATOR, NewBytesSentOnChannel);
  7835. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  7836. }
  7837. else
  7838. return RPC_S_OK;
  7839. }
  7840. else
  7841. {
  7842. ASSERT(SendContext->TrafficType == http2ttRTS);
  7843. // fall through to sending below
  7844. }
  7845. }
  7846. Mutex.Clear();
  7847. // either channel got reset or this was RTS traffic. Fall through to
  7848. // sending
  7849. }
  7850. // update BytesSentOnChannel in thread safe manner
  7851. do
  7852. {
  7853. LocalBytesSentOnChannel = BytesSentOnChannel;
  7854. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  7855. }
  7856. while (InterlockedCompareExchange((LONG *)&BytesSentOnChannel,
  7857. NewBytesSentOnChannel,
  7858. LocalBytesSentOnChannel) != LocalBytesSentOnChannel);
  7859. }
  7860. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  7861. if (ChannelReplacementNeeded && (RpcStatus == RPC_S_OK))
  7862. {
  7863. #if DBG
  7864. DbgPrintEx(DPFLTR_RPCPROXY_ID,
  7865. DPFLTR_TRACE_LEVEL,
  7866. "RPCRT4: Indicating channel needs recycling %p %d\n",
  7867. this,
  7868. IsServer);
  7869. #endif // DBG
  7870. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHANNEL_RECYCLE, HTTP2LOG_OT_CDATA_ORIGINATOR, NewBytesSentOnChannel);
  7871. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  7872. }
  7873. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  7874. return RpcStatus;
  7875. }
  7876. void HTTP2ChannelDataOriginator::Abort (
  7877. IN RPC_STATUS RpcStatus
  7878. )
  7879. {
  7880. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CDATA_ORIGINATOR, RpcStatus);
  7881. // we have a bunch of sends carrying ref-counts, etc.
  7882. // We must make sure they are completed.
  7883. HTTP2TransportChannel::Abort(RpcStatus);
  7884. // we know we are synchronized with everybody else
  7885. if (!RpcpIsListEmpty(&BufferQueueHead))
  7886. {
  7887. AbortStatus = RpcStatus;
  7888. (void) COMMON_PostRuntimeEvent(CHANNEL_DATA_ORIGINATOR_DIRECT_SEND,
  7889. this
  7890. );
  7891. }
  7892. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CDATA_ORIGINATOR, RpcStatus);
  7893. }
  7894. void HTTP2ChannelDataOriginator::FreeObject (
  7895. void
  7896. )
  7897. /*++
  7898. Routine Description:
  7899. Frees the object. Acts like a destructor for the
  7900. channel.
  7901. Arguments:
  7902. Return Value:
  7903. --*/
  7904. {
  7905. if (LowerLayer)
  7906. LowerLayer->FreeObject();
  7907. HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  7908. }
  7909. void HTTP2ChannelDataOriginator::Reset (
  7910. void
  7911. )
  7912. /*++
  7913. Routine Description:
  7914. Reset the channel for next open/send/receive. This is
  7915. used in submission context only and implies there are no
  7916. pending operations on the channel. It is used on the client
  7917. during opening the connection to do quick negotiation on the
  7918. same connection instead of opening a new connection every time.
  7919. Arguments:
  7920. Return Value:
  7921. --*/
  7922. {
  7923. #if DBG
  7924. RawDataAlreadySent = FALSE;
  7925. #endif // DBG
  7926. ASSERT(RpcpIsListEmpty(&BufferQueueHead));
  7927. LowerLayer->Reset();
  7928. }
  7929. void HTTP2ChannelDataOriginator::GetBufferQueue (
  7930. OUT LIST_ENTRY *NewQueueHead
  7931. )
  7932. /*++
  7933. Routine Description:
  7934. Grab all queued buffers and pile them on the list head
  7935. that we passed to it. All refcounts must be removed (i.e.
  7936. undone). Called in submission context only and we know there
  7937. will be no more sends. Therefore we are single threaded.
  7938. Arguments:
  7939. NewQueueHead - new queue heads to pile buffers on
  7940. Return Value:
  7941. --*/
  7942. {
  7943. LIST_ENTRY *CurrentListEntry;
  7944. LIST_ENTRY *NextListEntry;
  7945. HTTP2SendContext *SendContext;
  7946. ASSERT(RpcpIsListEmpty(NewQueueHead));
  7947. CurrentListEntry = BufferQueueHead.Flink;
  7948. while (CurrentListEntry != &BufferQueueHead)
  7949. {
  7950. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7951. SendContext->SetListEntryUnused();
  7952. NextListEntry = CurrentListEntry->Flink;
  7953. RpcpfInsertHeadList(NewQueueHead, CurrentListEntry);
  7954. UpperLayer->SendCancelled(SendContext);
  7955. CurrentListEntry = NextListEntry;
  7956. }
  7957. RpcpInitializeListHead(&BufferQueueHead);
  7958. }
  7959. RPC_STATUS HTTP2ChannelDataOriginator::DirectSendComplete (
  7960. OUT BOOL *IsServer,
  7961. OUT void **SendContext,
  7962. OUT BUFFER *Buffer,
  7963. OUT UINT *BufferLength
  7964. )
  7965. /*++
  7966. Routine Description:
  7967. Direct send complete notification. Complete the send
  7968. passing it only through channels that have seen it (i.e.
  7969. above us). Note that we will get one notification for
  7970. all buffered sends. We must empty the whole queue, and post
  7971. one notification for each buffer in the queue
  7972. Arguments:
  7973. IsServer - in all cases MUST be set to TRUE or FALSE.
  7974. SendContext - on output contains the send context as
  7975. seen by the runtime
  7976. Buffer - on output the buffer that we tried to send
  7977. BufferLength - on output the length of the buffer we tried to send
  7978. Return Value:
  7979. RPC_S_OK to return error to runtime
  7980. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  7981. RPC_S_* error - return error to runtime
  7982. --*/
  7983. {
  7984. LIST_ENTRY *CurrentListEntry;
  7985. HTTP2SendContext *CurrentSendContext;
  7986. RPC_STATUS RpcStatus;
  7987. BOOL PostAnotherReceive;
  7988. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_CDATA_ORIGINATOR,
  7989. !RpcpIsListEmpty(&BufferQueueHead));
  7990. *IsServer = this->IsServer;
  7991. // this should only get called when we are aborted. This
  7992. // ensures that we are single threaded in the code
  7993. // below
  7994. TopChannel->VerifyAborted();
  7995. CurrentListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  7996. ASSERT(CurrentListEntry != &BufferQueueHead);
  7997. CurrentSendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7998. CurrentSendContext->SetListEntryUnused();
  7999. ASSERT(AbortStatus != RPC_S_OK);
  8000. RpcStatus = HTTP2TransportChannel::SendComplete(AbortStatus, CurrentSendContext);
  8001. PostAnotherReceive = !(RpcpIsListEmpty(&BufferQueueHead));
  8002. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8003. {
  8004. // this will return to the runtime. Make sure it is valid
  8005. if (this->IsServer)
  8006. I_RpcTransVerifyServerRuntimeCallFromContext(CurrentSendContext);
  8007. else
  8008. I_RpcTransVerifyClientRuntimeCallFromContext(CurrentSendContext);
  8009. *SendContext = CurrentSendContext;
  8010. *Buffer = CurrentSendContext->pWriteBuffer;
  8011. *BufferLength = CurrentSendContext->maxWriteBuffer;
  8012. }
  8013. else
  8014. {
  8015. // the packet was a transport packet - it won't be seen by the runtime
  8016. *SendContext = NULL;
  8017. *Buffer = NULL;
  8018. *BufferLength = 0;
  8019. }
  8020. RpcStatus = AsyncCompleteHelper(RpcStatus);
  8021. // do not touch this pointer after here unless the list was not-empty
  8022. // (which implies we still have refcounts)
  8023. if (PostAnotherReceive)
  8024. {
  8025. (void) COMMON_PostRuntimeEvent(CHANNEL_DATA_ORIGINATOR_DIRECT_SEND,
  8026. this
  8027. );
  8028. }
  8029. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_CDATA_ORIGINATOR,
  8030. PostAnotherReceive);
  8031. return RpcStatus;
  8032. }
  8033. RPC_STATUS HTTP2ChannelDataOriginator::RestartChannel (
  8034. void
  8035. )
  8036. /*++
  8037. Routine Description:
  8038. Restart the channel. Somehow the channel lifetime became
  8039. fully available again, and we can start from 0. This happens
  8040. when the out proxy renegotiates the out channel with the client
  8041. and we can keep using the server channels again.
  8042. Arguments:
  8043. Return Value:
  8044. RPC_S_OK
  8045. RPC_S_* error
  8046. --*/
  8047. {
  8048. LIST_ENTRY *CurrentListEntry;
  8049. HTTP2SendContext *SendContext;
  8050. ULONG NewBytesSentOnChannel = 0;
  8051. ULONG BytesForThisSend;
  8052. RPC_STATUS RpcStatus;
  8053. // the channel must have been plugged
  8054. ASSERT(BytesSentOnChannel > NonreservedLifetime);
  8055. Mutex.Request();
  8056. // grab all queued packets and send them out
  8057. CurrentListEntry = BufferQueueHead.Flink;
  8058. while (CurrentListEntry != &BufferQueueHead)
  8059. {
  8060. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  8061. SendContext->SetListEntryUnused();
  8062. ASSERT(SendContext->TrafficType == http2ttData);
  8063. BytesForThisSend = SendContext->maxWriteBuffer;
  8064. // assume success of the send and remove the element from the queue.
  8065. // This is necessary because if the send succeeds, there is a race
  8066. // condition with the send complete path
  8067. (void) RpcpfRemoveHeadList(&BufferQueueHead);
  8068. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  8069. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  8070. if (RpcStatus != RPC_S_OK)
  8071. {
  8072. // failure. We should issue send complete for all queued sends
  8073. // including the current one. However, it is easier for us to add back
  8074. // the currently failed send and return failure to caller. Caller will
  8075. // abort and there we will issue send complete for all pending sends.
  8076. SendContext->SetListEntryUsed();
  8077. RpcpfInsertHeadList(&BufferQueueHead, CurrentListEntry);
  8078. Mutex.Clear();
  8079. // return failure to the caller. This will cause the caller to abort the
  8080. // channel, and all sends will be completed.
  8081. return RpcStatus;
  8082. }
  8083. NewBytesSentOnChannel += BytesForThisSend;
  8084. ASSERT(NewBytesSentOnChannel < NonreservedLifetime);
  8085. // process the next element (which by now has become the first since
  8086. // we removed the successfully sent one).
  8087. CurrentListEntry = BufferQueueHead.Flink;
  8088. }
  8089. // reset the counters
  8090. ChannelReplacementTriggered = FALSE;
  8091. BytesSentOnChannel = NewBytesSentOnChannel;
  8092. Mutex.Clear();
  8093. return RPC_S_OK;
  8094. }
  8095. RPC_STATUS HTTP2ChannelDataOriginator::NotifyTrafficSent (
  8096. IN ULONG TrafficSentSize
  8097. )
  8098. /*++
  8099. Routine Description:
  8100. Notifies the channel that bytes were sent on the wire. Channel
  8101. reports back whether channel recycling should occur.
  8102. Arguments:
  8103. TrafficSentSize - the number of bytes sent.
  8104. Return Value:
  8105. RPC_S_OK or RPC_P_CHANNEL_NEEDS_RECYCLING.
  8106. --*/
  8107. {
  8108. ULONG LocalBytesSentOnChannel;
  8109. ULONG NewBytesSentOnChannel;
  8110. BOOL ChannelReplacementNeeded;
  8111. ChannelReplacementNeeded = FALSE;
  8112. // this is very rare. Don't bother to take the mutex opportunistically.
  8113. // Just make sure that we do use interlocks because no all paths take
  8114. // the mutex. The mutex synchronizes us with Restart
  8115. Mutex.Request();
  8116. LocalBytesSentOnChannel = BytesSentOnChannel;
  8117. NewBytesSentOnChannel = LocalBytesSentOnChannel + TrafficSentSize;
  8118. if (NewBytesSentOnChannel > NonreservedLifetime)
  8119. {
  8120. if (ChannelReplacementTriggered == FALSE)
  8121. {
  8122. ChannelReplacementNeeded = TRUE;
  8123. ChannelReplacementTriggered = TRUE;
  8124. }
  8125. }
  8126. Mutex.Clear();
  8127. // update BytesSentOnChannel in thread safe manner
  8128. do
  8129. {
  8130. LocalBytesSentOnChannel = BytesSentOnChannel;
  8131. NewBytesSentOnChannel = LocalBytesSentOnChannel + TrafficSentSize;
  8132. }
  8133. while (InterlockedCompareExchange((LONG *)&BytesSentOnChannel,
  8134. NewBytesSentOnChannel,
  8135. LocalBytesSentOnChannel) != LocalBytesSentOnChannel);
  8136. if (ChannelReplacementNeeded)
  8137. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  8138. else
  8139. return RPC_S_OK;
  8140. }
  8141. /*********************************************************************
  8142. HTTP2Channel
  8143. *********************************************************************/
  8144. RPC_STATUS HTTP2Channel::Send (
  8145. IN OUT HTTP2SendContext *SendContext
  8146. )
  8147. /*++
  8148. Routine Description:
  8149. Send request
  8150. Arguments:
  8151. SendContext - the send context
  8152. Return Value:
  8153. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8154. --*/
  8155. {
  8156. RPC_STATUS RpcStatus;
  8157. RpcStatus = BeginSubmitAsync();
  8158. if (RpcStatus != RPC_S_OK)
  8159. return RpcStatus;
  8160. RpcStatus = LowerLayer->Send(SendContext);
  8161. FinishSubmitAsync();
  8162. if ((RpcStatus != RPC_S_OK)
  8163. && (RpcStatus != ERROR_IO_PENDING)
  8164. && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  8165. {
  8166. RemoveReference(); // remove the reference for the async send
  8167. }
  8168. return(RpcStatus);
  8169. }
  8170. RPC_STATUS HTTP2Channel::Receive (
  8171. IN HTTP2TrafficType TrafficType
  8172. )
  8173. /*++
  8174. Routine Description:
  8175. Receive request
  8176. Arguments:
  8177. TrafficType - the type of traffic we want to receive
  8178. Return Value:
  8179. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8180. --*/
  8181. {
  8182. RPC_STATUS RpcStatus;
  8183. RpcStatus = BeginSubmitAsync();
  8184. if (RpcStatus != RPC_S_OK)
  8185. return RpcStatus;
  8186. RpcStatus = LowerLayer->Receive(TrafficType);
  8187. FinishSubmitAsync();
  8188. if (RpcStatus != RPC_S_OK)
  8189. RemoveReference(); // remove the reference for the async receive
  8190. return(RpcStatus);
  8191. }
  8192. RPC_STATUS HTTP2Channel::SendComplete (
  8193. IN RPC_STATUS EventStatus,
  8194. IN OUT HTTP2SendContext *SendContext
  8195. )
  8196. /*++
  8197. Routine Description:
  8198. Send complete notification
  8199. Arguments:
  8200. EventStatus - status of the operation
  8201. SendContext - the send context
  8202. Return Value:
  8203. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8204. --*/
  8205. {
  8206. RPC_STATUS RpcStatus;
  8207. RpcStatus = CheckSendCompleteForSync(EventStatus,
  8208. SendContext
  8209. );
  8210. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8211. {
  8212. RpcStatus = ForwardUpSendComplete(EventStatus,
  8213. SendContext
  8214. );
  8215. }
  8216. return RpcStatus;
  8217. }
  8218. RPC_STATUS HTTP2Channel::ReceiveComplete (
  8219. IN RPC_STATUS EventStatus,
  8220. IN HTTP2TrafficType TrafficType,
  8221. IN BYTE *Buffer,
  8222. IN UINT BufferLength
  8223. )
  8224. /*++
  8225. Routine Description:
  8226. Receive complete notification complete notification
  8227. Arguments:
  8228. EventStatus - status of the operation
  8229. TrafficType - the type of traffic we have received
  8230. Buffer - the received buffer (success only)
  8231. BufferLength - the length of the received buffer (success only)
  8232. Return Value:
  8233. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8234. --*/
  8235. {
  8236. RPC_STATUS RpcStatus;
  8237. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_CHANNEL, (ULONG_PTR)EventStatus);
  8238. RpcStatus = CheckReceiveCompleteForSync(EventStatus,
  8239. TrafficType,
  8240. Buffer,
  8241. BufferLength
  8242. );
  8243. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8244. {
  8245. RpcStatus = ForwardUpReceiveComplete(EventStatus,
  8246. Buffer,
  8247. BufferLength
  8248. );
  8249. }
  8250. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_CHANNEL, (ULONG_PTR)RpcStatus);
  8251. return RpcStatus;
  8252. }
  8253. RPC_STATUS HTTP2Channel::SyncSend (
  8254. IN HTTP2TrafficType TrafficType,
  8255. IN ULONG BufferLength,
  8256. IN BYTE *Buffer,
  8257. IN BOOL fDisableCancelCheck,
  8258. IN ULONG Timeout,
  8259. IN BASE_ASYNC_OBJECT *Connection,
  8260. IN HTTP2SendContext *SendContext
  8261. )
  8262. /*++
  8263. Routine Description:
  8264. Emulate a sync send using lower level async primitives
  8265. Arguments:
  8266. TrafficType - the type of traffic
  8267. BufferLength - the length of the buffer
  8268. Buffer - the buffer to send
  8269. fDisableCancelCheck - don't do checks for cancels. Can be
  8270. used as optimization
  8271. Timeout - the call timeout
  8272. Connection - the transport connection object. Used for cancelling.
  8273. SendContext - a memory block of sufficient size to initialize a send context
  8274. Return Value:
  8275. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8276. --*/
  8277. {
  8278. RPC_STATUS RpcStatus;
  8279. SendContext->u.SyncEvent = I_RpcTransGetThreadEvent();
  8280. ResetEvent(SendContext->u.SyncEvent);
  8281. SendContext->SetListEntryUnused();
  8282. SendContext->maxWriteBuffer = BufferLength;
  8283. SendContext->pWriteBuffer = Buffer;
  8284. // SendContext->Write.pAsyncObject = NULL; // this will be initialized in the bottom layer
  8285. SendContext->Write.ol.Internal = STATUS_PENDING;
  8286. SendContext->TrafficType = http2ttData;
  8287. SendContext->Write.ol.OffsetHigh = 0;
  8288. SendContext->Flags = 0;
  8289. SendContext->UserData = 0;
  8290. RpcStatus = HTTP2Channel::Send(SendContext);
  8291. return RpcStatus;
  8292. }
  8293. RPC_STATUS HTTP2Channel::ForwardTraffic (
  8294. IN BYTE *Packet,
  8295. IN ULONG PacketLength
  8296. )
  8297. /*++
  8298. Routine Description:
  8299. On receiving channels forwards to the sending channel.
  8300. On sending channels sends down. This implementation
  8301. is for a sending channel (since all sending channels
  8302. are the same). Receiving channels must override it.
  8303. Arguments:
  8304. Packet - the packet to forward
  8305. PacketLength - the length of the packet
  8306. Return Value:
  8307. RPC_S_OK or other RPC_S_* errors for error
  8308. --*/
  8309. {
  8310. HTTP2SendContext *SendContext;
  8311. SendContext = AllocateAndInitializeContextFromPacket(Packet,
  8312. PacketLength
  8313. );
  8314. if (SendContext != NULL)
  8315. {
  8316. return Send(SendContext);
  8317. }
  8318. else
  8319. return RPC_S_OUT_OF_MEMORY;
  8320. }
  8321. RPC_STATUS HTTP2Channel::ForwardFlowControlAck (
  8322. IN ULONG BytesReceivedForAck,
  8323. IN ULONG WindowForAck
  8324. )
  8325. /*++
  8326. Routine Description:
  8327. Forwards a flow control ack. Receiving channels don't
  8328. need this. Sending channels must override to forward
  8329. to the right place.
  8330. Arguments:
  8331. BytesReceivedForAck - the bytes received when the ACK was issued
  8332. WindowForAck - the free window when the ACK was issued.
  8333. Return Value:
  8334. RPC_S_OK or RPC_S_*
  8335. --*/
  8336. {
  8337. // we should never be here
  8338. ASSERT(0);
  8339. return RPC_S_INTERNAL_ERROR;
  8340. }
  8341. RPC_STATUS HTTP2Channel::AsyncCompleteHelper (
  8342. IN RPC_STATUS CurrentStatus
  8343. )
  8344. /*++
  8345. Routine Description:
  8346. Helper routine that helps complete an async operation
  8347. Arguments:
  8348. CurrentStatus - the current status of the operation
  8349. Return Value:
  8350. The status to return to the runtime.
  8351. --*/
  8352. {
  8353. HTTP2VirtualConnection *VirtualConnection;
  8354. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  8355. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  8356. if (CurrentStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  8357. {
  8358. // recycle the parent connection
  8359. VirtualConnection = LockParentPointer();
  8360. if (VirtualConnection)
  8361. {
  8362. CurrentStatus = VirtualConnection->RecycleChannel(
  8363. TRUE // IsFromUpcall
  8364. );
  8365. UnlockParentPointer();
  8366. }
  8367. else
  8368. {
  8369. CurrentStatus = RPC_S_OK;
  8370. }
  8371. }
  8372. else if ((CurrentStatus != RPC_S_OK)
  8373. &&
  8374. (CurrentStatus != RPC_P_PACKET_CONSUMED))
  8375. {
  8376. // if this failed, abort the whole connection
  8377. AbortConnection(CurrentStatus);
  8378. }
  8379. RemoveReference();
  8380. return CurrentStatus;
  8381. }
  8382. void HTTP2Channel::Abort (
  8383. IN RPC_STATUS RpcStatus
  8384. )
  8385. /*++
  8386. Routine Description:
  8387. Aborts the channel and all of the stack below it. The
  8388. request must come from above or from neutral context -
  8389. never from submit context from below. Otherwise we
  8390. will deadlock when we drain the upcalls
  8391. Arguments:
  8392. RpcStatus - the error to abort with
  8393. Return Value:
  8394. --*/
  8395. {
  8396. BOOL Result;
  8397. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CHANNEL, RpcStatus);
  8398. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  8399. Result = InitiateAbort();
  8400. if (Result)
  8401. {
  8402. SetAbortReason(RpcStatus);
  8403. // forward it down
  8404. LowerLayer->Abort(RpcStatus);
  8405. }
  8406. }
  8407. void HTTP2Channel::AbortConnection (
  8408. IN RPC_STATUS AbortReason
  8409. )
  8410. /*++
  8411. Routine Description:
  8412. Aborts the virtual connection.
  8413. Arguments:
  8414. RpcStatus - the error to abort with
  8415. Return Value:
  8416. --*/
  8417. {
  8418. HTTP2VirtualConnection *VirtualConnection;
  8419. // abort the parent connection
  8420. VirtualConnection = LockParentPointer();
  8421. if (VirtualConnection)
  8422. {
  8423. VirtualConnection->AbortChannels(AbortReason);
  8424. UnlockParentPointer();
  8425. }
  8426. else
  8427. {
  8428. // abort this channel at least
  8429. Abort(AbortReason);
  8430. }
  8431. }
  8432. void HTTP2Channel::AbortAndDestroyConnection (
  8433. IN RPC_STATUS AbortStatus
  8434. )
  8435. /*++
  8436. Routine Description:
  8437. Aborts and destroys the virtual connection.
  8438. Arguments:
  8439. AbortStatus - the status to abort the connection
  8440. with.
  8441. Return Value:
  8442. Note: The method is idempotent
  8443. --*/
  8444. {
  8445. HTTP2VirtualConnection *VirtualConnection;
  8446. BOOL Result;
  8447. // first, tell connection to destroy itself (almost entirely)
  8448. VirtualConnection = LockParentPointer();
  8449. if (VirtualConnection == NULL)
  8450. {
  8451. // abort ourselves at least
  8452. Abort(AbortStatus);
  8453. return;
  8454. }
  8455. Result = VirtualConnection->AbortAndDestroy(TRUE, // IsFromChannel
  8456. ChannelId,
  8457. AbortStatus);
  8458. UnlockParentPointer();
  8459. // if somebody is already destroying it, just return
  8460. if (Result == FALSE)
  8461. return;
  8462. // because we have called AbortAndDestroy, we know the connection
  8463. // will stay for us. Synchronize with upcalls from this channel
  8464. DrainUpcallsAndFreeParent();
  8465. // now VirtualConnection is a pointer disconnected from everybody
  8466. // that we can destroy at our leisure
  8467. delete VirtualConnection;
  8468. }
  8469. RPC_STATUS HTTP2Channel::CheckSendCompleteForSync (
  8470. IN RPC_STATUS EventStatus,
  8471. IN OUT HTTP2SendContext *SendContext
  8472. )
  8473. /*++
  8474. Routine Description:
  8475. Send complete notification. Checks for sync operation,
  8476. and if yes, completes the sync send anc consumes
  8477. the packet.
  8478. Arguments:
  8479. EventStatus - status of the operation
  8480. SendContext - the send context
  8481. Return Value:
  8482. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8483. --*/
  8484. {
  8485. // was this a sync send?
  8486. if (SendContext->u.SyncEvent)
  8487. {
  8488. // yes, consume it
  8489. SendContext->Write.ol.Internal = (ULONG)EventStatus;
  8490. SendContext->Write.ol.OffsetHigh = 1;
  8491. SetEvent(SendContext->u.SyncEvent);
  8492. return RPC_P_PACKET_CONSUMED;
  8493. }
  8494. return RPC_S_OK;
  8495. }
  8496. RPC_STATUS HTTP2Channel::ForwardUpSendComplete (
  8497. IN RPC_STATUS EventStatus,
  8498. IN OUT HTTP2SendContext *SendContext
  8499. )
  8500. /*++
  8501. Routine Description:
  8502. Send complete notification. Forwards the send complete to the
  8503. virtual connection.
  8504. Arguments:
  8505. EventStatus - status of the operation
  8506. SendContext - the send context
  8507. Return Value:
  8508. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8509. --*/
  8510. {
  8511. HTTP2VirtualConnection *VirtualConnection;
  8512. RPC_STATUS RpcStatus;
  8513. BOOL IsRTSPacket;
  8514. VirtualConnection = LockParentPointer();
  8515. // if parent has already detached, just return back
  8516. if (VirtualConnection == NULL)
  8517. {
  8518. // in some cases the parent will detach without aborting
  8519. if (EventStatus == RPC_S_OK)
  8520. {
  8521. if (SendContext->TrafficType == http2ttRTS)
  8522. RpcStatus = RPC_P_PACKET_CONSUMED;
  8523. else
  8524. RpcStatus = EventStatus; // already ok
  8525. }
  8526. else
  8527. {
  8528. // Abort in these cases (Abort is idempotent)
  8529. Abort(EventStatus);
  8530. RpcStatus = EventStatus;
  8531. }
  8532. IsRTSPacket = (SendContext->TrafficType == http2ttRTS);
  8533. FreeSendContextAndPossiblyData(SendContext);
  8534. if (IsRTSPacket)
  8535. return RPC_P_PACKET_CONSUMED;
  8536. else
  8537. return RpcStatus;
  8538. }
  8539. RpcStatus = VirtualConnection->SendComplete(EventStatus,
  8540. SendContext,
  8541. ChannelId
  8542. );
  8543. UnlockParentPointer();
  8544. return RpcStatus;
  8545. }
  8546. RPC_STATUS HTTP2Channel::CheckReceiveCompleteForSync (
  8547. IN RPC_STATUS EventStatus,
  8548. IN HTTP2TrafficType TrafficType,
  8549. IN BYTE *Buffer,
  8550. IN UINT BufferLength
  8551. )
  8552. /*++
  8553. Routine Description:
  8554. Receive complete notification. Checks if the receive was
  8555. sync, and if yes, fires event and consumes the packet. For
  8556. base class it's always not for us (base class does not
  8557. support sync receives)
  8558. Arguments:
  8559. EventStatus - status of the operation
  8560. TrafficType - the type of traffic we received
  8561. Buffer - the received buffer (success only)
  8562. BufferLength - the length of the received buffer (success only)
  8563. Return Value:
  8564. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8565. --*/
  8566. {
  8567. // not for us after all. Let it continue
  8568. return RPC_S_OK;
  8569. }
  8570. RPC_STATUS HTTP2Channel::ForwardUpReceiveComplete (
  8571. IN RPC_STATUS EventStatus,
  8572. IN BYTE *Buffer,
  8573. IN UINT BufferLength
  8574. )
  8575. /*++
  8576. Routine Description:
  8577. Receive complete notification. Forwards the receive
  8578. complete to the virtual connection
  8579. Arguments:
  8580. EventStatus - status of the operation
  8581. Buffer - the received buffer (success only)
  8582. BufferLength - the length of the received buffer (success only)
  8583. Return Value:
  8584. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8585. --*/
  8586. {
  8587. HTTP2VirtualConnection *VirtualConnection;
  8588. RPC_STATUS RpcStatus;
  8589. VirtualConnection = LockParentPointer();
  8590. // if parent has already detached, just return back
  8591. if (VirtualConnection == NULL)
  8592. {
  8593. // in some cases the parent will detach without aborting
  8594. // Abort in these cases (Abort is idempotent)
  8595. Abort(RPC_P_CONNECTION_SHUTDOWN);
  8596. return RPC_P_PACKET_CONSUMED;
  8597. }
  8598. RpcStatus = VirtualConnection->ReceiveComplete(EventStatus,
  8599. Buffer,
  8600. BufferLength,
  8601. ChannelId
  8602. );
  8603. UnlockParentPointer();
  8604. if (RpcStatus == RPC_P_ABORT_NEEDED)
  8605. {
  8606. // in some cases the parent cannot abort because the channel
  8607. // is already detached from the parent. In such cases it will
  8608. // tell us to abort. (Abort is idempotent)
  8609. Abort(RPC_P_CONNECTION_SHUTDOWN);
  8610. RpcStatus = RPC_P_PACKET_CONSUMED;
  8611. }
  8612. return RpcStatus;
  8613. }
  8614. RPC_STATUS HTTP2Channel::SetKeepAliveTimeout (
  8615. IN BOOL TurnOn,
  8616. IN BOOL bProtectIO,
  8617. IN KEEPALIVE_TIMEOUT_UNITS Units,
  8618. IN OUT KEEPALIVE_TIMEOUT KATime,
  8619. IN ULONG KAInterval OPTIONAL
  8620. )
  8621. /*++
  8622. Routine Description:
  8623. Change the keep alive value on the channel
  8624. Arguments:
  8625. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  8626. are turned off.
  8627. bProtectIO - non-zero if IO needs to be protected against async close
  8628. of the connection.
  8629. Units - in what units is KATime
  8630. KATime - how much to wait before turning on keep alives
  8631. KAInterval - the interval between keep alives
  8632. Return Value:
  8633. RPC_S_OK or other RPC_S_* errors for error
  8634. --*/
  8635. {
  8636. // many channels don't support this and
  8637. // shouldn't be called with it. Those who do support it
  8638. // should override it.
  8639. ASSERT(FALSE);
  8640. return RPC_S_INTERNAL_ERROR;
  8641. }
  8642. RPC_STATUS HTTP2Channel::LastPacketSentNotification (
  8643. IN HTTP2SendContext *LastSendContext
  8644. )
  8645. /*++
  8646. Routine Description:
  8647. When a lower channel wants to notify the top
  8648. channel that the last packet has been sent,
  8649. they call this function. Must be called from
  8650. an upcall/neutral context. Only flow control
  8651. senders support past packet notifications
  8652. Arguments:
  8653. LastSendContext - the context we're sending
  8654. Return Value:
  8655. The value to return to the bottom channel/runtime.
  8656. --*/
  8657. {
  8658. ASSERT(0);
  8659. return RPC_S_INTERNAL_ERROR;
  8660. }
  8661. void HTTP2Channel::SendCancelled (
  8662. IN HTTP2SendContext *SendContext
  8663. )
  8664. /*++
  8665. Routine Description:
  8666. A lower channel cancelled a send already passed through this channel.
  8667. Arguments:
  8668. SendContext - the send context of the send that was cancelled
  8669. Return Value:
  8670. --*/
  8671. {
  8672. RemoveReference();
  8673. }
  8674. void HTTP2Channel::PingTrafficSentNotify (
  8675. IN ULONG PingTrafficSize
  8676. )
  8677. /*++
  8678. Routine Description:
  8679. Notifies a channel that ping traffic has been sent.
  8680. Arguments:
  8681. PingTrafficSize - the size of the ping traffic sent.
  8682. --*/
  8683. {
  8684. // nobody should be here. Channels that use that must
  8685. // override.
  8686. ASSERT(0);
  8687. }
  8688. void HTTP2Channel::FreeObject (
  8689. void
  8690. )
  8691. /*++
  8692. Routine Description:
  8693. Frees a client in channel object
  8694. Arguments:
  8695. Return Value:
  8696. --*/
  8697. {
  8698. // make sure we have been aborted
  8699. ASSERT(Aborted.GetInteger() > 0);
  8700. LowerLayer->FreeObject();
  8701. // the client channel is the top of the stack. Just free us
  8702. // which will free the whole stack
  8703. delete this;
  8704. }
  8705. RPC_STATUS HTTP2Channel::ForwardFlowControlAckOnDefaultChannel (
  8706. IN BOOL IsInChannel,
  8707. IN ForwardDestinations Destination,
  8708. IN ULONG BytesReceivedForAck,
  8709. IN ULONG WindowForAck
  8710. )
  8711. /*++
  8712. Routine Description:
  8713. Forwards a flow control ack on the default channel
  8714. Arguments:
  8715. IsInChannel - non-zero if the IN channel is to be used. FALSE
  8716. otherwise
  8717. Destination - where to forward to.
  8718. BytesReceivedForAck - the bytes received when the ACK was issued
  8719. WindowForAck - the free window when the ACK was issued.
  8720. Return Value:
  8721. RPC_S_OK or RPC_S_*
  8722. Notes:
  8723. If on an endpoint, called from a neutral context only. Proxies
  8724. call it in submission context.
  8725. --*/
  8726. {
  8727. HTTP2VirtualConnection *VirtualConnection;
  8728. HTTP2SendContext *SendContext;
  8729. RPC_STATUS RpcStatus;
  8730. VirtualConnection = LockParentPointer();
  8731. if (VirtualConnection == NULL)
  8732. return RPC_P_CONNECTION_SHUTDOWN;
  8733. // allocate and initalize the flow control ACK packet
  8734. SendContext = AllocateAndInitializeFlowControlAckPacketWithDestination (
  8735. Destination,
  8736. BytesReceivedForAck,
  8737. WindowForAck,
  8738. VirtualConnection->MapChannelIdToCookie(ChannelId)
  8739. );
  8740. if (SendContext == NULL)
  8741. return RPC_S_OUT_OF_MEMORY;
  8742. RpcStatus = VirtualConnection->SendTrafficOnDefaultChannel(IsInChannel,
  8743. SendContext
  8744. );
  8745. UnlockParentPointer();
  8746. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  8747. FreeRTSPacket(SendContext);
  8748. return RpcStatus;
  8749. }
  8750. RPC_STATUS HTTP2Channel::ForwardFlowControlAckOnThisChannel (
  8751. IN ULONG BytesReceivedForAck,
  8752. IN ULONG WindowForAck,
  8753. IN BOOL NonChannelData
  8754. )
  8755. /*++
  8756. Routine Description:
  8757. Forwards a flow control ack on this channel
  8758. Arguments:
  8759. BytesReceivedForAck - the bytes received when the ACK was issued
  8760. WindowForAck - the free window when the ACK was issued.
  8761. NonChannelData - non-zero if the data being sent don't go on the HTTP
  8762. channel. FALSE if they do
  8763. Return Value:
  8764. RPC_S_OK or RPC_S_*
  8765. Notes:
  8766. This must be called in upcall or neutral context only
  8767. --*/
  8768. {
  8769. HTTP2SendContext *SendContext;
  8770. RPC_STATUS RpcStatus;
  8771. HTTP2VirtualConnection *VirtualConnection;
  8772. VirtualConnection = LockParentPointer();
  8773. if (VirtualConnection == NULL)
  8774. return RPC_P_CONNECTION_SHUTDOWN;
  8775. // allocate and initalize the flow control ACK packet
  8776. SendContext = AllocateAndInitializeFlowControlAckPacket (
  8777. BytesReceivedForAck,
  8778. WindowForAck,
  8779. VirtualConnection->MapChannelIdToCookie(ChannelId)
  8780. );
  8781. UnlockParentPointer();
  8782. if (SendContext == NULL)
  8783. return RPC_S_OUT_OF_MEMORY;
  8784. if (NonChannelData)
  8785. SendContext->Flags |= SendContextFlagNonChannelData;
  8786. RpcStatus = Send(SendContext);
  8787. // this can be called on the server, or on the proxy. If on the server,
  8788. // it will be called with NonChannelData. This means we cannot have
  8789. // channel recycle indication here.
  8790. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  8791. if (RpcStatus != RPC_S_OK)
  8792. {
  8793. FreeRTSPacket(SendContext);
  8794. }
  8795. return RpcStatus;
  8796. }
  8797. RPC_STATUS HTTP2Channel::HandleSendResultFromNeutralContext (
  8798. IN RPC_STATUS CurrentStatus
  8799. )
  8800. /*++
  8801. Routine Description:
  8802. Handles the result code from send from a neutral context.
  8803. This includes checking for channel recycling and intiating
  8804. one if necessary.
  8805. Arguments:
  8806. CurrentStatus - the status from the send operation
  8807. Return Value:
  8808. RPC_S_OK or RPC_S_*. Callers may ignore it since all cleanup was
  8809. done.
  8810. Notes:
  8811. This must be called in upcall or neutral context only
  8812. --*/
  8813. {
  8814. RPC_STATUS RpcStatus;
  8815. HTTP2VirtualConnection *VirtualConnection;
  8816. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  8817. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  8818. if (CurrentStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  8819. {
  8820. // recycle the parent connection
  8821. VirtualConnection = LockParentPointer();
  8822. if (VirtualConnection)
  8823. {
  8824. RpcStatus = VirtualConnection->RecycleChannel(
  8825. TRUE // IsFromUpcall
  8826. );
  8827. UnlockParentPointer();
  8828. if (RpcStatus != RPC_S_OK)
  8829. {
  8830. // if this failed, abort the whole connection
  8831. AbortConnection(CurrentStatus);
  8832. }
  8833. CurrentStatus = RpcStatus;
  8834. }
  8835. else
  8836. {
  8837. // nothing to do - the channel is dying anyway
  8838. CurrentStatus = RPC_P_CONNECTION_SHUTDOWN;
  8839. }
  8840. }
  8841. return CurrentStatus;
  8842. }
  8843. RPC_STATUS HTTP2Channel::IsInChannel (
  8844. OUT BOOL *InChannel
  8845. )
  8846. /*++
  8847. Routine Description:
  8848. Checks if the current channel is an in channel or an
  8849. out channel.
  8850. Arguments:
  8851. InChannel - on output will be set to non-zero if this is an
  8852. in channel. It will be set to 0 if this is an out channel.
  8853. Undefined on failure.
  8854. Return Value:
  8855. RPC_S_OK or RPC_P_CONNECTION_SHUTDOWN. If the parent has detached,
  8856. RPC_P_CONNECTION_SHUTDOWN will be returned. In all other cases
  8857. success is returned.
  8858. --*/
  8859. {
  8860. HTTP2VirtualConnection *VirtualConnection;
  8861. VirtualConnection = LockParentPointer();
  8862. if (VirtualConnection)
  8863. {
  8864. VirtualConnection->VerifyValidChannelId(ChannelId);
  8865. *InChannel = VirtualConnection->IsInChannel(ChannelId);
  8866. UnlockParentPointer();
  8867. return RPC_S_OK;
  8868. }
  8869. else
  8870. return RPC_P_CONNECTION_SHUTDOWN;
  8871. }
  8872. /*********************************************************************
  8873. HTTP2VirtualConnection
  8874. *********************************************************************/
  8875. RPC_STATUS HTTP2VirtualConnection::Send (
  8876. IN UINT Length,
  8877. IN BUFFER Buffer,
  8878. IN PVOID SendContext
  8879. )
  8880. /*++
  8881. Routine Description:
  8882. Send on an HTTP client virtual connection. Proxies don't
  8883. override that. Other virtual connections may override it.
  8884. Arguments:
  8885. Length - The length of the data to send.
  8886. Buffer - The data to send.
  8887. SendContext - A buffer of at least SendContextSize bytes
  8888. which will be used during the call and returned
  8889. when the send completes.
  8890. Return Value:
  8891. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8892. Note:
  8893. Can be called from runtime/neutral context only.
  8894. --*/
  8895. {
  8896. HTTP2ChannelPointer *ChannelPtr;
  8897. HTTP2Channel *Channel;
  8898. HTTP2SendContext *HttpSendContext;
  8899. RPC_STATUS RpcStatus;
  8900. HttpSendContext = (HTTP2SendContext *)SendContext;
  8901. HttpSendContext->SetListEntryUnused();
  8902. HttpSendContext->maxWriteBuffer = Length;
  8903. HttpSendContext->pWriteBuffer = Buffer;
  8904. HttpSendContext->TrafficType = http2ttData;
  8905. HttpSendContext->u.SyncEvent = NULL;
  8906. HttpSendContext->Flags = 0;
  8907. HttpSendContext->UserData = 0;
  8908. Channel = LockDefaultSendChannel(&ChannelPtr);
  8909. if (Channel)
  8910. {
  8911. RpcStatus = Channel->Send(HttpSendContext);
  8912. ChannelPtr->UnlockChannelPointer();
  8913. }
  8914. else
  8915. {
  8916. RpcStatus = RPC_P_SEND_FAILED;
  8917. }
  8918. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  8919. FALSE // IsFromUpcall
  8920. );
  8921. if (RpcStatus != RPC_S_OK)
  8922. {
  8923. Abort();
  8924. if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  8925. RpcStatus = RPC_P_SEND_FAILED;
  8926. }
  8927. VALIDATE(RpcStatus)
  8928. {
  8929. RPC_S_OK,
  8930. RPC_S_OUT_OF_MEMORY,
  8931. RPC_S_OUT_OF_RESOURCES,
  8932. RPC_P_SEND_FAILED
  8933. } END_VALIDATE;
  8934. return RpcStatus;
  8935. }
  8936. RPC_STATUS HTTP2VirtualConnection::Receive (
  8937. void
  8938. )
  8939. /*++
  8940. Routine Description:
  8941. Post a receive on a HTTP client virtual connection.
  8942. Arguments:
  8943. Return Value:
  8944. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8945. --*/
  8946. {
  8947. HTTP2ChannelPointer *ChannelPtr;
  8948. HTTP2Channel *Channel;
  8949. RPC_STATUS RpcStatus;
  8950. Channel = LockDefaultReceiveChannel(&ChannelPtr);
  8951. if (Channel)
  8952. {
  8953. RpcStatus = Channel->Receive(http2ttData);
  8954. ChannelPtr->UnlockChannelPointer();
  8955. }
  8956. else
  8957. {
  8958. RpcStatus = RPC_P_CONNECTION_CLOSED;
  8959. }
  8960. if (RpcStatus != RPC_S_OK)
  8961. {
  8962. Abort();
  8963. }
  8964. return RpcStatus;
  8965. }
  8966. RPC_STATUS HTTP2VirtualConnection::SyncSend (
  8967. IN ULONG BufferLength,
  8968. IN BYTE *Buffer,
  8969. IN BOOL fDisableShutdownCheck,
  8970. IN BOOL fDisableCancelCheck,
  8971. IN ULONG Timeout
  8972. )
  8973. /*++
  8974. Routine Description:
  8975. Do a sync send on an HTTP connection.
  8976. Arguments:
  8977. BufferLength - the length of the data to send.
  8978. Buffer - the data to send.
  8979. fDisableShutdownCheck - ignored
  8980. fDisableCancelCheck - runtime indicates no cancel
  8981. will be attempted on this send. Can be used
  8982. as optimization hint by the transport
  8983. Timeout - send timeout (call timeout)
  8984. Return Value:
  8985. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8986. --*/
  8987. {
  8988. RPC_STATUS RpcStatus;
  8989. RPC_STATUS RpcStatus2;
  8990. HTTP2SendContext LocalSendContext;
  8991. HTTP2Channel *Channel;
  8992. HTTP2ChannelPointer *ChannelPtr;
  8993. // we will convert a sync send to an async send
  8994. // make sure there is a thread to pick up the completion
  8995. RpcStatus = HTTPTransInfo->CreateThread();
  8996. if (RpcStatus != RPC_S_OK)
  8997. {
  8998. VALIDATE(RpcStatus)
  8999. {
  9000. RPC_S_OK,
  9001. RPC_S_OUT_OF_MEMORY,
  9002. RPC_S_OUT_OF_RESOURCES,
  9003. RPC_P_SEND_FAILED,
  9004. RPC_S_CALL_CANCELLED,
  9005. RPC_P_RECEIVE_COMPLETE,
  9006. RPC_P_TIMEOUT
  9007. } END_VALIDATE;
  9008. return RpcStatus;
  9009. }
  9010. Channel = LockDefaultSendChannel (&ChannelPtr);
  9011. if (Channel == NULL)
  9012. {
  9013. return RPC_P_SEND_FAILED;
  9014. }
  9015. RpcStatus = Channel->SyncSend(http2ttData,
  9016. BufferLength,
  9017. Buffer,
  9018. fDisableCancelCheck,
  9019. Timeout,
  9020. this,
  9021. &LocalSendContext
  9022. );
  9023. ChannelPtr->UnlockChannelPointer();
  9024. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  9025. {
  9026. // get the ball rolling with the recycle
  9027. RpcStatus = RecycleChannel(
  9028. FALSE // IsFromUpcall
  9029. );
  9030. // ok or not, we have to wait for IO to complete
  9031. RpcStatus2 = WaitForSyncSend(this,
  9032. &LocalSendContext,
  9033. this,
  9034. fDisableCancelCheck,
  9035. Timeout
  9036. );
  9037. if ((RpcStatus2 == RPC_S_OK) && (RpcStatus != RPC_S_OK))
  9038. RpcStatus2 = RpcStatus;
  9039. if ((RpcStatus2 == RPC_P_CONNECTION_SHUTDOWN)
  9040. || (RpcStatus2 == RPC_P_RECEIVE_FAILED)
  9041. || (RpcStatus2 == RPC_P_CONNECTION_CLOSED) )
  9042. RpcStatus2 = RPC_P_SEND_FAILED;
  9043. VALIDATE(RpcStatus2)
  9044. {
  9045. RPC_S_OK,
  9046. RPC_S_OUT_OF_MEMORY,
  9047. RPC_S_OUT_OF_RESOURCES,
  9048. RPC_P_SEND_FAILED,
  9049. RPC_S_CALL_CANCELLED,
  9050. RPC_P_RECEIVE_COMPLETE,
  9051. RPC_P_TIMEOUT
  9052. } END_VALIDATE;
  9053. return RpcStatus2;
  9054. }
  9055. else
  9056. {
  9057. if (RpcStatus == RPC_S_OK)
  9058. {
  9059. RpcStatus = WaitForSyncSend(this,
  9060. &LocalSendContext,
  9061. this,
  9062. fDisableCancelCheck,
  9063. Timeout
  9064. );
  9065. }
  9066. if (RpcStatus != RPC_S_OK)
  9067. {
  9068. if ((RpcStatus == RPC_P_RECEIVE_FAILED)
  9069. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  9070. || (RpcStatus == RPC_P_CONNECTION_SHUTDOWN) )
  9071. RpcStatus = RPC_P_SEND_FAILED;
  9072. }
  9073. VALIDATE(RpcStatus)
  9074. {
  9075. RPC_S_OK,
  9076. RPC_S_OUT_OF_MEMORY,
  9077. RPC_S_OUT_OF_RESOURCES,
  9078. RPC_P_SEND_FAILED,
  9079. RPC_S_CALL_CANCELLED,
  9080. RPC_P_RECEIVE_COMPLETE,
  9081. RPC_P_TIMEOUT
  9082. } END_VALIDATE;
  9083. return RpcStatus;
  9084. }
  9085. }
  9086. RPC_STATUS HTTP2VirtualConnection::SyncRecv (
  9087. IN BYTE **Buffer,
  9088. IN ULONG *BufferLength,
  9089. IN ULONG Timeout
  9090. )
  9091. /*++
  9092. Routine Description:
  9093. Do a sync receive on an HTTP connection.
  9094. Arguments:
  9095. Buffer - if successful, points to a buffer containing the next PDU.
  9096. BufferLength - if successful, contains the length of the message.
  9097. Timeout - the amount of time to wait for the receive. If -1, we wait
  9098. infinitely.
  9099. Return Value:
  9100. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9101. --*/
  9102. {
  9103. // nobody should be calling SyncRecv on the base connection
  9104. ASSERT(0);
  9105. return RPC_S_INTERNAL_ERROR;
  9106. }
  9107. void HTTP2VirtualConnection::Close (
  9108. IN BOOL DontFlush
  9109. )
  9110. /*++
  9111. Routine Description:
  9112. Closes an HTTP connection. Proxies don't
  9113. override that. Other virtual connections may override it.
  9114. Arguments:
  9115. DontFlush - non-zero if all buffers need to be flushed
  9116. before closing the connection. Zero otherwise.
  9117. Return Value:
  9118. --*/
  9119. {
  9120. Abort();
  9121. }
  9122. RPC_STATUS HTTP2VirtualConnection::TurnOnOffKeepAlives (
  9123. IN BOOL TurnOn,
  9124. IN BOOL bProtectIO,
  9125. IN BOOL IsFromUpcall,
  9126. IN KEEPALIVE_TIMEOUT_UNITS Units,
  9127. IN OUT KEEPALIVE_TIMEOUT KATime,
  9128. IN ULONG KAInterval OPTIONAL
  9129. )
  9130. /*++
  9131. Routine Description:
  9132. Turns on keep alives for HTTP. Proxies don't
  9133. override that. Other virtual connections may override it.
  9134. Arguments:
  9135. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  9136. are turned off.
  9137. bProtectIO - non-zero if IO needs to be protected against async close
  9138. of the connection.
  9139. IsFromUpcall - non-zero if called from upcall context. Zero otherwise.
  9140. Units - in what units is KATime
  9141. KATime - how much to wait before turning on keep alives
  9142. KAInterval - the interval between keep alives
  9143. Return Value:
  9144. RPC_S_OK or RPC_S_* / Win32 errors on failure
  9145. Note:
  9146. If we use it on the server, we must protect
  9147. the connection against async aborts.
  9148. --*/
  9149. {
  9150. // The server doesn't support this for Whistler. Think
  9151. // about it for Longhorn. Client overrides it.
  9152. ASSERT(FALSE);
  9153. return RPC_S_INTERNAL_ERROR;
  9154. }
  9155. RPC_STATUS HTTP2VirtualConnection::QueryClientAddress (
  9156. OUT RPC_CHAR **pNetworkAddress
  9157. )
  9158. /*++
  9159. Routine Description:
  9160. Returns the IP address of the client on a connection as a string.
  9161. This is a server side function. Assert on the client. Proxies don't
  9162. override that. Other virtual connections may override it.
  9163. Arguments:
  9164. NetworkAddress - Will contain string on success.
  9165. Return Value:
  9166. RPC_S_OK or other RPC_S_* errors for error
  9167. --*/
  9168. {
  9169. ASSERT(FALSE);
  9170. return RPC_S_INTERNAL_ERROR;
  9171. }
  9172. RPC_STATUS HTTP2VirtualConnection::QueryLocalAddress (
  9173. IN OUT void *Buffer,
  9174. IN OUT unsigned long *BufferSize,
  9175. OUT unsigned long *AddressFormat
  9176. )
  9177. /*++
  9178. Routine Description:
  9179. Returns the local IP address of a connection.
  9180. This is a server side function. Assert on the client. Proxies don't
  9181. override that. Other virtual connections may override it.
  9182. Arguments:
  9183. Buffer - The buffer that will receive the output address
  9184. BufferSize - the size of the supplied Buffer on input. On output the
  9185. number of bytes written to the buffer. If the buffer is too small
  9186. to receive all the output data, ERROR_MORE_DATA is returned,
  9187. nothing is written to the buffer, and BufferSize is set to
  9188. the size of the buffer needed to return all the data.
  9189. AddressFormat - a constant indicating the format of the returned address.
  9190. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  9191. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  9192. Return Value:
  9193. RPC_S_OK or other RPC_S_* errors for error
  9194. --*/
  9195. {
  9196. ASSERT(FALSE);
  9197. return RPC_S_INTERNAL_ERROR;
  9198. }
  9199. RPC_STATUS HTTP2VirtualConnection::QueryClientId(
  9200. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  9201. )
  9202. /*++
  9203. Routine Description:
  9204. For secure protocols (which TCP/IP is not) this is supposed to
  9205. give an ID which will be shared by all clients from the same
  9206. process. This prevents one user from grabbing another users
  9207. association group and using their context handles.
  9208. Since TCP/IP is not secure we return the IP address of the
  9209. client machine. This limits the attacks to other processes
  9210. running on the client machine which is better than nothing.
  9211. This is a server side function. Assert on the client. Proxies don't
  9212. override that. Other virtual connections may override it.
  9213. Arguments:
  9214. ClientProcess - Transport identification of the "client".
  9215. Return Value:
  9216. RPC_S_OK or other RPC_S_* errors for error
  9217. --*/
  9218. {
  9219. ASSERT(0);
  9220. return RPC_S_INTERNAL_ERROR;
  9221. }
  9222. void HTTP2VirtualConnection::AbortChannels (
  9223. IN RPC_STATUS RpcStatus
  9224. )
  9225. /*++
  9226. Routine Description:
  9227. Aborts an HTTP connection but does not disconnect
  9228. the channels. Can be called from above, upcall, or
  9229. neutral context, but not from submit context!
  9230. Arguments:
  9231. RpcStatus - the error to abort the channels with
  9232. Return Value:
  9233. --*/
  9234. {
  9235. HTTP2ChannelPointer *Channels[4];
  9236. HTTP2Channel *CurrentChannel;
  9237. int i;
  9238. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  9239. // quick optimization. Don't abort already aborted channels
  9240. // All channels are protected against double abortion - this
  9241. // is just an optimization
  9242. if (Aborted.GetInteger() > 0)
  9243. return;
  9244. Channels[0] = &InChannels[0];
  9245. Channels[1] = &InChannels[1];
  9246. Channels[2] = &OutChannels[0];
  9247. Channels[3] = &OutChannels[1];
  9248. for (i = 0; i < 4; i ++)
  9249. {
  9250. CurrentChannel = Channels[i]->LockChannelPointer();
  9251. if (CurrentChannel)
  9252. {
  9253. CurrentChannel->Abort(RpcStatus);
  9254. Channels[i]->UnlockChannelPointer();
  9255. }
  9256. }
  9257. }
  9258. BOOL HTTP2VirtualConnection::AbortAndDestroy (
  9259. IN BOOL IsFromChannel,
  9260. IN int CallingChannelId,
  9261. IN RPC_STATUS AbortStatus
  9262. )
  9263. /*++
  9264. Routine Description:
  9265. Aborts and destroys a connection. This is safe to
  9266. call from an upcall, as long as the calling channel
  9267. passes in its channel id. Actually the destruction
  9268. does not happen here. The caller has the obligation
  9269. to destroy it after synchronizing its upcalls.
  9270. Arguments:
  9271. IsFromChannel - non-zero if the call comes from a channel.
  9272. Zero otherwise.
  9273. CallingChannelId - the id of the calling channel. If IsFromChannel
  9274. is FALSE, this argument should be ignored.
  9275. AbortStatus - the error to abort the connection with.
  9276. Return Value:
  9277. non-zero - caller may destroy the connection.
  9278. FALSE - destruction is already in progress. Caller
  9279. must not destroy the connection.
  9280. --*/
  9281. {
  9282. if (IsFromChannel)
  9283. {
  9284. VerifyValidChannelId(CallingChannelId);
  9285. }
  9286. // abort the channels themselves
  9287. AbortChannels(AbortStatus);
  9288. // we got to the destructive phase of the abort
  9289. // guard against double aborts
  9290. if (Aborted.Increment() > 1)
  9291. return FALSE;
  9292. DisconnectChannels(IsFromChannel, CallingChannelId);
  9293. // we have disconnected all but the channel on which we received
  9294. // this call.
  9295. return TRUE;
  9296. }
  9297. void HTTP2VirtualConnection::LastPacketSentNotification (
  9298. IN int ChannelId,
  9299. IN HTTP2SendContext *LastSendContext
  9300. )
  9301. /*++
  9302. Routine Description:
  9303. When a channel wants to notify the virtual connection
  9304. that the last packet has been sent, they call this function.
  9305. Must be called from an upcall/neutral context. Only flow control
  9306. senders generated past packet notifications
  9307. Arguments:
  9308. ChannelId - the channelfor which this notification is.
  9309. LastSendContext - the send context for the last send
  9310. Return Value:
  9311. --*/
  9312. {
  9313. ASSERT(0);
  9314. }
  9315. RPC_STATUS HTTP2VirtualConnection::PostReceiveOnChannel (
  9316. IN HTTP2ChannelPointer *ChannelPtr,
  9317. IN HTTP2TrafficType TrafficType
  9318. )
  9319. /*++
  9320. Routine Description:
  9321. Posts a receceive on specified channel
  9322. Arguments:
  9323. ChannelPtr - the channel pointer to post the receive on
  9324. TrafficType - the type of traffic we wish to receive
  9325. Return Value:
  9326. RPC_S_OK or RPC_S_* error
  9327. --*/
  9328. {
  9329. HTTP2Channel *Channel;
  9330. RPC_STATUS RpcStatus;
  9331. Channel = ChannelPtr->LockChannelPointer();
  9332. if (Channel)
  9333. {
  9334. RpcStatus = Channel->Receive(TrafficType);
  9335. ChannelPtr->UnlockChannelPointer();
  9336. }
  9337. else
  9338. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9339. return RpcStatus;
  9340. }
  9341. RPC_STATUS HTTP2VirtualConnection::PostReceiveOnDefaultChannel (
  9342. IN BOOL IsInChannel,
  9343. IN HTTP2TrafficType TrafficType
  9344. )
  9345. /*++
  9346. Routine Description:
  9347. Posts a receceive on the default channel for the specified type
  9348. Arguments:
  9349. IsInChannel - if non-zero, post a receive on default in channel.
  9350. If 0, post a receive on default out channel
  9351. TrafficType - the type of traffic we wish to receive
  9352. Return Value:
  9353. RPC_S_OK or RPC_S_* error
  9354. --*/
  9355. {
  9356. HTTP2Channel *Channel;
  9357. HTTP2ChannelPointer *ChannelPtr;
  9358. RPC_STATUS RpcStatus;
  9359. if (IsInChannel)
  9360. Channel = LockDefaultInChannel(&ChannelPtr);
  9361. else
  9362. Channel = LockDefaultOutChannel(&ChannelPtr);
  9363. if (Channel)
  9364. {
  9365. RpcStatus = Channel->Receive(TrafficType);
  9366. ChannelPtr->UnlockChannelPointer();
  9367. }
  9368. else
  9369. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9370. return RpcStatus;
  9371. }
  9372. RPC_STATUS HTTP2VirtualConnection::ForwardTrafficToChannel (
  9373. IN HTTP2ChannelPointer *ChannelPtr,
  9374. IN BYTE *Packet,
  9375. IN ULONG PacketLength
  9376. )
  9377. /*++
  9378. Routine Description:
  9379. Forwards the given packet on the given channel
  9380. Arguments:
  9381. ChannelPtr - the channel pointer
  9382. Packet - the packet to forward
  9383. PacketLength - the length of the packet to forward
  9384. Return Value:
  9385. RPC_S_OK or RPC_S_* error
  9386. --*/
  9387. {
  9388. HTTP2Channel *Channel;
  9389. RPC_STATUS RpcStatus;
  9390. Channel = ChannelPtr->LockChannelPointer();
  9391. if (Channel)
  9392. {
  9393. RpcStatus = Channel->ForwardTraffic(Packet, PacketLength);
  9394. ChannelPtr->UnlockChannelPointer();
  9395. }
  9396. else
  9397. {
  9398. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9399. }
  9400. return RpcStatus;
  9401. }
  9402. RPC_STATUS HTTP2VirtualConnection::ForwardTrafficToDefaultChannel (
  9403. IN BOOL IsInChannel,
  9404. IN BYTE *Packet,
  9405. IN ULONG PacketLength
  9406. )
  9407. /*++
  9408. Routine Description:
  9409. Forwards the given packet on the given channel
  9410. Arguments:
  9411. IsInChannel - if non-zero, forward to default in channel.
  9412. If 0, forward to default out channel
  9413. Packet - the packet to forward
  9414. PacketLength - the length of the packet to forward
  9415. Return Value:
  9416. RPC_S_OK or RPC_S_* error
  9417. --*/
  9418. {
  9419. HTTP2Channel *Channel;
  9420. HTTP2ChannelPointer *ChannelPtr;
  9421. RPC_STATUS RpcStatus;
  9422. if (IsInChannel)
  9423. Channel = LockDefaultInChannel(&ChannelPtr);
  9424. else
  9425. Channel = LockDefaultOutChannel(&ChannelPtr);
  9426. if (Channel)
  9427. {
  9428. RpcStatus = Channel->ForwardTraffic(Packet, PacketLength);
  9429. ChannelPtr->UnlockChannelPointer();
  9430. }
  9431. else
  9432. {
  9433. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9434. }
  9435. return RpcStatus;
  9436. }
  9437. RPC_STATUS HTTP2VirtualConnection::SendTrafficOnChannel (
  9438. IN HTTP2ChannelPointer *ChannelPtr,
  9439. IN HTTP2SendContext *SendContext
  9440. )
  9441. /*++
  9442. Routine Description:
  9443. Sends the given packet on the given channel
  9444. Arguments:
  9445. ChannelPtr - the channel pointer on which to send.
  9446. SendContext - context to send
  9447. Return Value:
  9448. RPC_S_OK or RPC_S_* error
  9449. --*/
  9450. {
  9451. HTTP2Channel *Channel;
  9452. RPC_STATUS RpcStatus;
  9453. Channel = ChannelPtr->LockChannelPointer();
  9454. if (Channel)
  9455. {
  9456. RpcStatus = Channel->Send(SendContext);
  9457. ChannelPtr->UnlockChannelPointer();
  9458. }
  9459. else
  9460. {
  9461. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9462. }
  9463. return RpcStatus;
  9464. }
  9465. RPC_STATUS HTTP2VirtualConnection::SendTrafficOnDefaultChannel (
  9466. IN BOOL IsInChannel,
  9467. IN HTTP2SendContext *SendContext
  9468. )
  9469. /*++
  9470. Routine Description:
  9471. Sends the given packet on the given channel
  9472. Arguments:
  9473. IsInChannel - if non-zero, send on default in channel.
  9474. If 0, send on default out channel
  9475. SendContext - context to send
  9476. Return Value:
  9477. RPC_S_OK or RPC_S_* error
  9478. --*/
  9479. {
  9480. HTTP2Channel *Channel;
  9481. HTTP2ChannelPointer *ChannelPtr;
  9482. RPC_STATUS RpcStatus;
  9483. if (IsInChannel)
  9484. Channel = LockDefaultInChannel(&ChannelPtr);
  9485. else
  9486. Channel = LockDefaultOutChannel(&ChannelPtr);
  9487. if (Channel)
  9488. {
  9489. RpcStatus = Channel->Send(SendContext);
  9490. ChannelPtr->UnlockChannelPointer();
  9491. }
  9492. else
  9493. {
  9494. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9495. }
  9496. return RpcStatus;
  9497. }
  9498. RPC_STATUS HTTP2VirtualConnection::RecycleChannel (
  9499. IN BOOL IsFromUpcall
  9500. )
  9501. /*++
  9502. Routine Description:
  9503. Initiates channel recycling. Each endpoint supports
  9504. initiating recycling of only one channel, so it knows
  9505. which one it is.
  9506. Endpoints override that. On proxies it shouldn't be called
  9507. at all.
  9508. Arguments:
  9509. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  9510. Return Value:
  9511. RPC_S_OK of the recycling operation started successfully.
  9512. RPC_S_* error for errors.
  9513. --*/
  9514. {
  9515. ASSERT(0);
  9516. return RPC_S_INTERNAL_ERROR;
  9517. }
  9518. RPC_STATUS HTTP2VirtualConnection::StartChannelRecyclingIfNecessary (
  9519. IN RPC_STATUS RpcStatus,
  9520. IN BOOL IsFromUpcall
  9521. )
  9522. /*++
  9523. Routine Description:
  9524. Checks the result of the send for channel recycle indication, and if one
  9525. is present, initiate channel recycle
  9526. Arguments:
  9527. RpcStatus - the return code from the Send operation.
  9528. IsFromUpcall - non-zero if this was called from an upcall. Zero otherwise.
  9529. Return Value:
  9530. RPC_S_* errors - the channel recycling failed to start.
  9531. any success code will be the passed in success code turned around.
  9532. If this function starts with a failure, the failure will be turned around
  9533. Notes:
  9534. May be called in an upcall or runtime context only.
  9535. --*/
  9536. {
  9537. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  9538. RpcStatus = RecycleChannel(IsFromUpcall);
  9539. return RpcStatus;
  9540. }
  9541. HTTP2Channel *HTTP2VirtualConnection::MapCookieToChannelPointer (
  9542. IN HTTP2Cookie *ChannelCookie,
  9543. OUT HTTP2ChannelPointer **ChannelPtr
  9544. )
  9545. /*++
  9546. Routine Description:
  9547. Maps a channel cookie to a channel pointer. A channel will be selected only if
  9548. it is the default channel as well. The returned channel is locked.
  9549. Arguments:
  9550. ChannelCookie - the cookie for the channel.
  9551. ChannelPtr - the channel pointer. On NULL return value this is undefined.
  9552. Return Value:
  9553. The channel if the channel was found or NULL
  9554. if the channel was not found. During some recycling scenarios
  9555. the channel may not be there, or the returning channel pointer
  9556. may have a detached channel
  9557. --*/
  9558. {
  9559. volatile int *DefaultChannelSelector;
  9560. int TargetChannelSelector;
  9561. HTTP2ChannelPointer *LocalChannelPtr;
  9562. HTTP2Channel *Channel;
  9563. if (InChannelCookies[0].Compare(ChannelCookie) == 0)
  9564. {
  9565. LocalChannelPtr = &InChannels[0];
  9566. DefaultChannelSelector = &DefaultInChannelSelector;
  9567. TargetChannelSelector = 0;
  9568. }
  9569. else if (InChannelCookies[1].Compare(ChannelCookie) == 0)
  9570. {
  9571. LocalChannelPtr = &InChannels[1];
  9572. DefaultChannelSelector = &DefaultInChannelSelector;
  9573. TargetChannelSelector = 1;
  9574. }
  9575. else if (OutChannelCookies[0].Compare(ChannelCookie) == 0)
  9576. {
  9577. LocalChannelPtr = &OutChannels[0];
  9578. DefaultChannelSelector = &DefaultOutChannelSelector;
  9579. TargetChannelSelector = 0;
  9580. }
  9581. else if (OutChannelCookies[1].Compare(ChannelCookie) == 0)
  9582. {
  9583. LocalChannelPtr = &OutChannels[1];
  9584. DefaultChannelSelector = &DefaultOutChannelSelector;
  9585. TargetChannelSelector = 1;
  9586. }
  9587. else
  9588. return NULL;
  9589. Channel = LocalChannelPtr->LockChannelPointer();
  9590. if (Channel)
  9591. {
  9592. if (*DefaultChannelSelector == TargetChannelSelector)
  9593. {
  9594. // if we locked the channel and it is the right channel,
  9595. // use it
  9596. *ChannelPtr = LocalChannelPtr;
  9597. return Channel;
  9598. }
  9599. LocalChannelPtr->UnlockChannelPointer();
  9600. }
  9601. return NULL;
  9602. }
  9603. HTTP2Channel *HTTP2VirtualConnection::MapCookieToAnyChannelPointer (
  9604. IN HTTP2Cookie *ChannelCookie,
  9605. OUT HTTP2ChannelPointer **ChannelPtr
  9606. )
  9607. /*++
  9608. Routine Description:
  9609. Maps a channel cookie to a channel pointer. Unlike MapCookieToChannelPointer,
  9610. channel will be selected regardless of whether it is default.The returned
  9611. channel is locked.
  9612. Arguments:
  9613. ChannelCookie - the cookie for the channel.
  9614. ChannelPtr - the channel pointer. On NULL return value this is undefined.
  9615. Return Value:
  9616. The channel if the channel was found or NULL
  9617. if the channel was not found. During some recycling scenarios
  9618. the channel may not be there, or the returning channel pointer
  9619. may have a detached channel
  9620. --*/
  9621. {
  9622. HTTP2ChannelPointer *LocalChannelPtr;
  9623. HTTP2Channel *Channel;
  9624. if (InChannelCookies[0].Compare(ChannelCookie) == 0)
  9625. {
  9626. LocalChannelPtr = &InChannels[0];
  9627. }
  9628. else if (InChannelCookies[1].Compare(ChannelCookie) == 0)
  9629. {
  9630. LocalChannelPtr = &InChannels[1];
  9631. }
  9632. else if (OutChannelCookies[0].Compare(ChannelCookie) == 0)
  9633. {
  9634. LocalChannelPtr = &OutChannels[0];
  9635. }
  9636. else if (OutChannelCookies[1].Compare(ChannelCookie) == 0)
  9637. {
  9638. LocalChannelPtr = &OutChannels[1];
  9639. }
  9640. else
  9641. return NULL;
  9642. Channel = LocalChannelPtr->LockChannelPointer();
  9643. if (Channel)
  9644. {
  9645. // if we locked the channel and it is the right channel,
  9646. // use it
  9647. *ChannelPtr = LocalChannelPtr;
  9648. return Channel;
  9649. }
  9650. return NULL;
  9651. }
  9652. HTTP2Channel *HTTP2VirtualConnection::LockDefaultSendChannel (
  9653. OUT HTTP2ChannelPointer **ChannelPtr
  9654. )
  9655. /*++
  9656. Routine Description:
  9657. Locks the send channel. Most connections don't override that.
  9658. Arguments:
  9659. ChannelPtr - on success, the channel pointer to use.
  9660. Return Value:
  9661. The locked channel or NULL (same semantics as LockDefaultOutChannel)
  9662. --*/
  9663. {
  9664. return LockDefaultOutChannel(ChannelPtr);
  9665. }
  9666. HTTP2Channel *HTTP2VirtualConnection::LockDefaultReceiveChannel (
  9667. OUT HTTP2ChannelPointer **ChannelPtr
  9668. )
  9669. /*++
  9670. Routine Description:
  9671. Locks the receive channel. Most connections don't override that.
  9672. Arguments:
  9673. ChannelPtr - on success, the channel pointer to use.
  9674. Return Value:
  9675. The locked channel or NULL (same semantics as LockDefaultInChannel)
  9676. --*/
  9677. {
  9678. return LockDefaultInChannel(ChannelPtr);
  9679. }
  9680. void HTTP2VirtualConnection::SetFirstInChannel (
  9681. IN HTTP2Channel *NewChannel
  9682. )
  9683. /*++
  9684. Routine Description:
  9685. Sets the passed in channel as first default in channel.
  9686. Typically used during building a stack.
  9687. Arguments:
  9688. NewChannel - new in channel.
  9689. Return Value:
  9690. --*/
  9691. {
  9692. int InChannelId;
  9693. InChannelId = AllocateChannelId();
  9694. DefaultInChannelSelector = 0;
  9695. NewChannel->SetChannelId(InChannelId);
  9696. InChannels[0].SetChannel(NewChannel);
  9697. InChannelIds[0] = InChannelId;
  9698. }
  9699. void HTTP2VirtualConnection::SetFirstOutChannel (
  9700. IN HTTP2Channel *NewChannel
  9701. )
  9702. /*++
  9703. Routine Description:
  9704. Sets the passed in channel as first default out channel.
  9705. Typically used during building a stack.
  9706. Arguments:
  9707. NewChannel - new out channel.
  9708. Return Value:
  9709. --*/
  9710. {
  9711. int OutChannelId;
  9712. OutChannelId = AllocateChannelId();
  9713. DefaultOutChannelSelector = 0;
  9714. NewChannel->SetChannelId(OutChannelId);
  9715. OutChannels[0].SetChannel(NewChannel);
  9716. OutChannelIds[0] = OutChannelId;
  9717. }
  9718. void HTTP2VirtualConnection::SetNonDefaultInChannel (
  9719. IN HTTP2Channel *NewChannel
  9720. )
  9721. /*++
  9722. Routine Description:
  9723. Sets the non default in channel. Used during channel
  9724. recycling. Note that this MUST be called by the code
  9725. that received RPC_P_CHANNEL_NEEDS_RECYCLING, because
  9726. it is not thread safe.
  9727. Arguments:
  9728. NewChannel - new in channel.
  9729. Return Value:
  9730. --*/
  9731. {
  9732. int InChannelId;
  9733. int NonDefaultInChannelSelector;
  9734. InChannelId = AllocateChannelId();
  9735. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  9736. NewChannel->SetChannelId(InChannelId);
  9737. InChannels[NonDefaultInChannelSelector].SetChannel(NewChannel);
  9738. InChannelIds[NonDefaultInChannelSelector] = InChannelId;
  9739. }
  9740. void HTTP2VirtualConnection::SetNonDefaultOutChannel (
  9741. IN HTTP2Channel *NewChannel
  9742. )
  9743. /*++
  9744. Routine Description:
  9745. Sets the non default out channel. Used during channel
  9746. recycling. Note that this MUST be called by the code
  9747. that received RPC_P_CHANNEL_NEEDS_RECYCLING, because
  9748. it is not thread safe.
  9749. Arguments:
  9750. NewChannel - new out channel.
  9751. Return Value:
  9752. --*/
  9753. {
  9754. int OutChannelId;
  9755. int NonDefaultOutChannelSelector;
  9756. OutChannelId = AllocateChannelId();
  9757. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  9758. NewChannel->SetChannelId(OutChannelId);
  9759. OutChannels[NonDefaultOutChannelSelector].SetChannel(NewChannel);
  9760. OutChannelIds[NonDefaultOutChannelSelector] = OutChannelId;
  9761. }
  9762. void HTTP2VirtualConnection::DisconnectChannels (
  9763. IN BOOL ExemptChannel,
  9764. IN int ExemptChannelId
  9765. )
  9766. /*++
  9767. Routine Description:
  9768. Disconnects all channels. Must be called from runtime
  9769. or neutral context. Cannot be called from upcall or
  9770. submit context unless an exempt channel is given
  9771. Note that call must synchronize to ensure we're the only
  9772. thread doing the disconnect
  9773. Arguments:
  9774. ExemptChannel - non-zero if ExemptChannelId contains a
  9775. valid exempt channel id. FALSE otherwise.
  9776. ExemptChannelId - if ExemptChannel is non-zero, this argument
  9777. is the id of a channel that will be disconnected, but not
  9778. synchronized with up calls.
  9779. If ExampleChannel is FALSE, this argument is undefined
  9780. Return Value:
  9781. --*/
  9782. {
  9783. HTTP2ChannelPointer *Channels[4];
  9784. int ChannelIds[4];
  9785. HTTP2Channel *CurrentChannel;
  9786. int i;
  9787. // we should be the only thread aborting - just disconnect everybody
  9788. Channels[0] = &InChannels[0];
  9789. ChannelIds[0] = InChannelIds[0];
  9790. Channels[1] = &InChannels[1];
  9791. ChannelIds[1] = InChannelIds[1];
  9792. Channels[2] = &OutChannels[0];
  9793. ChannelIds[2] = OutChannelIds[0];
  9794. Channels[3] = &OutChannels[1];
  9795. ChannelIds[3] = OutChannelIds[1];
  9796. for (i = 0; i < 4; i ++)
  9797. {
  9798. if ((ExemptChannel == FALSE)
  9799. || ((ExemptChannel != FALSE) && (ExemptChannelId != ChannelIds[i])))
  9800. {
  9801. // disconnect the channel
  9802. Channels[i]->FreeChannelPointer(TRUE,
  9803. FALSE, // CalledFromUpcallContext
  9804. FALSE, // Abort
  9805. RPC_S_OK
  9806. );
  9807. }
  9808. else
  9809. {
  9810. Channels[i]->FreeChannelPointer(FALSE,
  9811. FALSE, // CalledFromUpcallContext
  9812. FALSE, // Abort
  9813. RPC_S_OK
  9814. );
  9815. }
  9816. }
  9817. }
  9818. /*********************************************************************
  9819. HTTP2ClientChannel
  9820. *********************************************************************/
  9821. const char *HeaderFragment1 = " http://";
  9822. const int HeaderFragment1Length = 8; // length of " http://"
  9823. const char *HeaderFragment2 = "/rpc/rpcproxy.dll?";
  9824. const int HeaderFragment2Length = 18; // length of /rpc/rpcproxy.dll?
  9825. const RPC_CHAR *HeaderFragment2W = L"/rpc/rpcproxy.dll?";
  9826. const int HeaderFragment2WLength = 36; // length of wide /rpc/rpcproxy.dll?
  9827. const char *HeaderFragment3 = ":";
  9828. const int HeaderFragment3Length = 1; // length of :
  9829. const RPC_CHAR *HeaderFragment3W = L":";
  9830. const int HeaderFragment3WLength = 2; // length of wide :
  9831. const char *HeaderFragment4 = " HTTP/1.1\r\nAccept:application/rpc\r\nUser-Agent:MSRPC\r\nHost:";
  9832. const int HeaderFragment4Length = 58; // length of " HTTP/1.1\r\nAccept:application/rpc\r\nUser-Agent:MSRPC\r\nHost:"
  9833. const char *HeaderFragment5 = "\r\nContent-Length:";
  9834. const int HeaderFragment5Length = 17; // "\r\nlength of Content-Length:"
  9835. const char *HeaderFragment6 = "\r\nConnection: Keep-Alive\r\nCache-control:no-cache\r\nPragma:no-cache\r\n\r\n";
  9836. const int HeaderFragment6Length = 69; // length of \r\nConnection: Keep-Alive\r\nCache-control:no-cache\r\nPragma:no-cache\r\n\r\n
  9837. const RPC_CHAR *HeaderAcceptType = L"application/rpc";
  9838. RPC_STATUS HTTP2ClientChannel::ClientOpen (
  9839. IN HTTPResolverHint *Hint,
  9840. IN const char *Verb,
  9841. IN int VerbLength,
  9842. IN BOOL InChannel,
  9843. IN BOOL ReplacementChannel,
  9844. IN BOOL UseWinHttp,
  9845. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials, OPTIONAL
  9846. IN ULONG ChosenAuthScheme, OPTIONAL
  9847. IN HTTP2WinHttpTransportChannel *WinHttpChannel, OPTIONAL
  9848. IN ULONG CallTimeout,
  9849. IN const BYTE *AdditionalData, OPTIONAL
  9850. IN ULONG AdditionalDataLength OPTIONAL
  9851. )
  9852. /*++
  9853. Routine Description:
  9854. Sends the HTTP establishment header on
  9855. the in/out channel.
  9856. Arguments:
  9857. Hint - the resolver hint
  9858. Verb - the verb to use.
  9859. VerbLength - the length of the verb (in characters, not including
  9860. null terminator).
  9861. InChannel - non-zero if this is an in channel open. In such case we use
  9862. the channel lifetime as the content length. If 0, this is an out
  9863. channel and we use the real content length + some additional space.
  9864. The additional space depends on the ReplacementChannel parameter
  9865. ReplacementChannel - non-zero if this is a replacement channel. Zero
  9866. otherwise. If it is a replacement channel, we add the size of D4/A3.
  9867. Else, we use the size of D1/A1. This is valid only for out channels
  9868. UseWinHttp - non-zero if we should use WinHttp for bottom level communications
  9869. HttpCredentials - the encrypted Http Credentials to use. Ignored unless UseWinHttp
  9870. is non-zero.
  9871. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  9872. WinHttpChannel - the winhttp channel to use for opening. Ignored unless UseWinHttp
  9873. is non-zero.
  9874. CallTimeout - the call timeout for this call.
  9875. AdditionalData - additional data to send with the header. Must be set iff
  9876. AdditionalDataLength != 0
  9877. AdditionalDataLength - the length of the additional data to send with the header.
  9878. Must be set iff AdditionalLength != NULL
  9879. Return Value:
  9880. RPC_S_OK or RPC_S_* error
  9881. --*/
  9882. {
  9883. ULONG MemorySize;
  9884. char *Buffer;
  9885. RPC_CHAR *BufferW;
  9886. RPC_CHAR *OriginalBufferW;
  9887. RPC_CHAR *VerbW;
  9888. char *Header;
  9889. char ServerPortString[6];
  9890. ULONG ServerPortStringLength;
  9891. HTTP2SendContext *SendContext;
  9892. RPC_STATUS RpcStatus;
  9893. char ContentLengthString[6];
  9894. ULONG AdditionalLength;
  9895. ULONG ContentLengthStringLength; // without terminating NULL
  9896. char *ContentLengthToUse;
  9897. // we have plenty of parameters. Verify them
  9898. // We can't have chosen auth scheme without credentials
  9899. // or WinHttpChannel
  9900. if (ChosenAuthScheme)
  9901. {
  9902. ASSERT(HttpCredentials);
  9903. ASSERT(WinHttpChannel);
  9904. }
  9905. // we can't have additional data without data and vice versa
  9906. if (AdditionalData)
  9907. {
  9908. ASSERT(AdditionalDataLength);
  9909. }
  9910. else
  9911. {
  9912. ASSERT(AdditionalDataLength == 0);
  9913. }
  9914. PortNumberToEndpointA(Hint->ServerPort, ServerPortString);
  9915. ServerPortStringLength = RpcpStringLengthA(ServerPortString);
  9916. // determine the content length
  9917. if (AdditionalData)
  9918. {
  9919. AdditionalLength = AdditionalDataLength;
  9920. if (!UseWinHttp)
  9921. {
  9922. RpcpItoa(AdditionalLength, ContentLengthString, 10);
  9923. ContentLengthStringLength = RpcpStringLengthA(ContentLengthString);
  9924. ContentLengthToUse = ContentLengthString;
  9925. }
  9926. }
  9927. else
  9928. {
  9929. if (InChannel == FALSE)
  9930. {
  9931. if (ReplacementChannel)
  9932. AdditionalLength = GetD4_A3TotalLength() + GetD4_A11TotalLength();
  9933. else
  9934. AdditionalLength = GetD1_A1TotalLength();
  9935. if (!UseWinHttp)
  9936. {
  9937. RpcpItoa(AdditionalLength, ContentLengthString, 10);
  9938. ContentLengthStringLength = RpcpStringLengthA(ContentLengthString);
  9939. ContentLengthToUse = ContentLengthString;
  9940. }
  9941. }
  9942. else
  9943. {
  9944. if (UseWinHttp)
  9945. {
  9946. AdditionalLength = DefaultChannelLifetime;
  9947. }
  9948. else
  9949. {
  9950. ContentLengthStringLength = DefaultChannelLifetimeStringLength;
  9951. ContentLengthToUse = DefaultChannelLifetimeString;
  9952. }
  9953. }
  9954. }
  9955. if (UseWinHttp)
  9956. {
  9957. ASSERT(WinHttpChannel != NULL);
  9958. VerbW = new RPC_CHAR[VerbLength + 1];
  9959. if (VerbW == NULL)
  9960. return RPC_S_OUT_OF_MEMORY;
  9961. FullAnsiToUnicode((char *)Verb, VerbW);
  9962. MemorySize = HeaderFragment2Length
  9963. + Hint->ServerNameLength
  9964. + HeaderFragment3Length
  9965. + ServerPortStringLength
  9966. + 1
  9967. ;
  9968. BufferW = (RPC_CHAR *)RpcAllocateBuffer(MemorySize * sizeof(RPC_CHAR));
  9969. if (BufferW == NULL)
  9970. {
  9971. delete [] VerbW;
  9972. return RPC_S_OUT_OF_MEMORY;
  9973. }
  9974. OriginalBufferW = BufferW;
  9975. RpcpMemoryCopy(BufferW, HeaderFragment2W, HeaderFragment2WLength);
  9976. BufferW += HeaderFragment2Length;
  9977. FullAnsiToUnicode(Hint->RpcServer, BufferW);
  9978. BufferW += Hint->ServerNameLength;
  9979. RpcpMemoryCopy(BufferW, HeaderFragment3W, HeaderFragment3WLength);
  9980. BufferW += HeaderFragment3Length;
  9981. FullAnsiToUnicode(ServerPortString, BufferW);
  9982. RpcStatus = WinHttpChannel->Open (Hint,
  9983. VerbW,
  9984. OriginalBufferW, // Url
  9985. HeaderAcceptType,
  9986. AdditionalLength,
  9987. CallTimeout,
  9988. HttpCredentials,
  9989. ChosenAuthScheme,
  9990. AdditionalData
  9991. );
  9992. delete [] VerbW;
  9993. RpcFreeBuffer(OriginalBufferW);
  9994. }
  9995. else
  9996. {
  9997. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext)
  9998. + VerbLength
  9999. + HeaderFragment1Length
  10000. + Hint->ProxyNameLength
  10001. + HeaderFragment2Length
  10002. + Hint->ServerNameLength
  10003. + HeaderFragment3Length
  10004. + ServerPortStringLength
  10005. + HeaderFragment4Length
  10006. + Hint->ProxyNameLength
  10007. + HeaderFragment5Length
  10008. + ContentLengthStringLength
  10009. + HeaderFragment6Length
  10010. ;
  10011. if (AdditionalDataLength)
  10012. MemorySize += AdditionalDataLength;
  10013. Buffer = (char *)RpcAllocateBuffer(MemorySize);
  10014. if (Buffer == NULL)
  10015. return RPC_S_OUT_OF_MEMORY;
  10016. SendContext = (HTTP2SendContext *)Buffer;
  10017. Buffer += SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext);
  10018. Header = Buffer;
  10019. RpcpMemoryCopy(Buffer, Verb, VerbLength);
  10020. Buffer += VerbLength;
  10021. RpcpMemoryCopy(Buffer, HeaderFragment1, HeaderFragment1Length);
  10022. Buffer += HeaderFragment1Length;
  10023. RpcpMemoryCopy(Buffer, Hint->RpcProxy, Hint->ProxyNameLength);
  10024. Buffer += Hint->ProxyNameLength;
  10025. RpcpMemoryCopy(Buffer, HeaderFragment2, HeaderFragment2Length);
  10026. Buffer += HeaderFragment2Length;
  10027. RpcpMemoryCopy(Buffer, Hint->RpcServer, Hint->ServerNameLength);
  10028. Buffer += Hint->ServerNameLength;
  10029. RpcpMemoryCopy(Buffer, HeaderFragment3, HeaderFragment3Length);
  10030. Buffer += HeaderFragment3Length;
  10031. RpcpMemoryCopy(Buffer, ServerPortString, ServerPortStringLength);
  10032. Buffer += ServerPortStringLength;
  10033. RpcpMemoryCopy(Buffer, HeaderFragment4, HeaderFragment4Length);
  10034. Buffer += HeaderFragment4Length;
  10035. RpcpMemoryCopy(Buffer, Hint->RpcProxy, Hint->ProxyNameLength);
  10036. Buffer += Hint->ProxyNameLength;
  10037. RpcpMemoryCopy(Buffer, HeaderFragment5, HeaderFragment5Length);
  10038. Buffer += HeaderFragment5Length;
  10039. RpcpMemoryCopy(Buffer, ContentLengthToUse, ContentLengthStringLength);
  10040. Buffer += ContentLengthStringLength;
  10041. RpcpMemoryCopy(Buffer, HeaderFragment6, HeaderFragment6Length);
  10042. if (AdditionalDataLength)
  10043. {
  10044. Buffer += HeaderFragment6Length;
  10045. RpcpMemoryCopy(Buffer, AdditionalData, AdditionalDataLength);
  10046. }
  10047. #if DBG
  10048. SendContext->ListEntryUsed = FALSE;
  10049. #endif
  10050. SendContext->maxWriteBuffer = MemorySize - SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext);
  10051. SendContext->pWriteBuffer = (BUFFER)Header;
  10052. SendContext->u.SyncEvent = NULL;
  10053. SendContext->TrafficType = http2ttRaw;
  10054. SendContext->Flags = 0;
  10055. SendContext->UserData = 0;
  10056. RpcStatus = BeginSubmitAsync();
  10057. if (RpcStatus != RPC_S_OK)
  10058. {
  10059. RpcFreeBuffer(SendContext);
  10060. return RpcStatus;
  10061. }
  10062. RpcStatus = LowerLayer->Send(SendContext);
  10063. FinishSubmitAsync();
  10064. if (RpcStatus != RPC_S_OK)
  10065. {
  10066. RpcFreeBuffer(SendContext);
  10067. RemoveReference();
  10068. }
  10069. }
  10070. return RpcStatus;
  10071. }
  10072. RPC_STATUS HTTP2ClientChannel::SendComplete (
  10073. IN RPC_STATUS EventStatus,
  10074. IN OUT HTTP2SendContext *SendContext
  10075. )
  10076. /*++
  10077. Routine Description:
  10078. Send complete notification
  10079. Arguments:
  10080. EventStatus - the status of the send
  10081. SendContext - send context
  10082. Return Value:
  10083. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10084. --*/
  10085. {
  10086. RPC_STATUS RpcStatus;
  10087. HTTP2VirtualConnection *VirtualConnection;
  10088. RpcStatus = HTTP2Channel::CheckSendCompleteForSync(EventStatus,
  10089. SendContext
  10090. );
  10091. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  10092. {
  10093. // is this our client open packet?
  10094. if (SendContext->TrafficType == http2ttRaw)
  10095. {
  10096. if (EventStatus != RPC_S_OK)
  10097. {
  10098. VirtualConnection = (HTTP2VirtualConnection *)LockParentPointer();
  10099. if (VirtualConnection != NULL)
  10100. {
  10101. VirtualConnection->Abort();
  10102. UnlockParentPointer();
  10103. }
  10104. }
  10105. RpcFreeBuffer(SendContext);
  10106. RpcStatus = RPC_P_PACKET_CONSUMED;
  10107. }
  10108. else if (RpcStatus == RPC_S_OK)
  10109. {
  10110. // doesn't seem like our traffic. Forward it up.
  10111. RpcStatus = ForwardUpSendComplete(EventStatus,
  10112. SendContext
  10113. );
  10114. }
  10115. else
  10116. {
  10117. // must be an error - just fall through
  10118. }
  10119. }
  10120. return RpcStatus;
  10121. }
  10122. RPC_STATUS HTTP2ClientChannel::CheckReceiveCompleteForSync (
  10123. IN RPC_STATUS EventStatus,
  10124. IN HTTP2TrafficType TrafficType,
  10125. IN BYTE *Buffer,
  10126. IN UINT BufferLength
  10127. )
  10128. /*++
  10129. Routine Description:
  10130. Receive complete notification. Checks if the receive was
  10131. sync, and if yes, fires event and consumes the packet.
  10132. Arguments:
  10133. EventStatus - status of the operation
  10134. TrafficType - the type of traffic we received
  10135. Buffer - the received buffer (success only)
  10136. BufferLength - the length of the received buffer (success only)
  10137. Return Value:
  10138. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10139. --*/
  10140. {
  10141. HANDLE hEvent;
  10142. // RTS receives are never sync even if there
  10143. // is a sync waiter
  10144. if (TrafficType == http2ttRTS)
  10145. return RPC_S_OK;
  10146. // was this a sync receive?
  10147. if (Ol.ReceiveOverlapped.hEvent)
  10148. {
  10149. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHECK_RECV_COMPLETE, HTTP2LOG_OT_CLIENT_CHANNEL, (ULONG_PTR)Buffer);
  10150. // yes, consume it
  10151. if (EventStatus == RPC_S_OK)
  10152. {
  10153. ASSERT(Buffer != NULL);
  10154. }
  10155. Ol.ReceiveOverlapped.Buffer = Buffer;
  10156. Ol.ReceiveOverlapped.BufferLength = BufferLength;
  10157. hEvent = Ol.ReceiveOverlapped.hEvent;
  10158. Ol.ReceiveOverlapped.Internal = (ULONG)EventStatus;
  10159. Ol.ReceiveOverlapped.IOCompleted = TRUE;
  10160. SetEvent(hEvent);
  10161. return RPC_P_PACKET_CONSUMED;
  10162. }
  10163. // wasn't for us after all. Let it continue
  10164. return RPC_S_OK;
  10165. }
  10166. void HTTP2ClientChannel::WaitInfiniteForSyncReceive (
  10167. void
  10168. )
  10169. /*++
  10170. Routine Description:
  10171. Waits infinitely for a sync recv to complete.
  10172. Channel must be aborted before this is called.
  10173. Arguments:
  10174. Return Value:
  10175. --*/
  10176. {
  10177. ASSERT(Aborted.GetInteger() > 0);
  10178. UTIL_WaitForSyncHTTP2IO(&Ol.Overlapped,
  10179. Ol.ReceiveOverlapped.hEvent,
  10180. FALSE, // Alertable
  10181. INFINITE);
  10182. }
  10183. RPC_STATUS HTTP2ClientChannel::SubmitSyncRecv (
  10184. IN HTTP2TrafficType TrafficType
  10185. )
  10186. /*++
  10187. Routine Description:
  10188. Submits a sync recv.
  10189. Arguments:
  10190. TrafficType - the type of traffic
  10191. Return Value:
  10192. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10193. --*/
  10194. {
  10195. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SYNC_RECV, HTTP2LOG_OT_CLIENT_CHANNEL, TrafficType);
  10196. // transfer the settings from parameters to the receive overlapped
  10197. Ol.ReceiveOverlapped.hEvent = I_RpcTransGetThreadEvent();
  10198. ResetEvent(Ol.ReceiveOverlapped.hEvent);
  10199. Ol.ReceiveOverlapped.IOCompleted = FALSE;
  10200. // submit the actual receive
  10201. return HTTP2Channel::Receive(TrafficType);
  10202. }
  10203. RPC_STATUS HTTP2ClientChannel::WaitForSyncRecv (
  10204. IN BYTE **Buffer,
  10205. IN ULONG *BufferLength,
  10206. IN ULONG Timeout,
  10207. IN ULONG ConnectionTimeout,
  10208. IN BASE_ASYNC_OBJECT *Connection,
  10209. OUT BOOL *AbortNeeded,
  10210. OUT BOOL *IoPending
  10211. )
  10212. /*++
  10213. Routine Description:
  10214. Waits for a sync receive to complete.
  10215. Arguments:
  10216. Buffer - on success will contain the received buffer. On failure
  10217. is undefined.
  10218. BufferLength - on success will contain the length of the buffer.
  10219. On failure is undefined.
  10220. Timeout - the call timeout
  10221. ConnectionTimeout - the connection timeout
  10222. Connection - the transport connection object
  10223. AbortNeeded - must be FALSE on entry. This function will set it to
  10224. non-zero if abort and wait are needed.
  10225. WaitPending - must be FALSE on entry. If on return there is an Io
  10226. pending, it will be set to non-zero
  10227. Return Value:
  10228. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10229. --*/
  10230. {
  10231. RPC_STATUS RpcStatus;
  10232. DWORD dwActualTimeout;
  10233. BOOL fWaitOnConnectionTimeout;
  10234. BOOL fSetKeepAliveVals;
  10235. KEEPALIVE_TIMEOUT KATimeout;
  10236. RPC_STATUS RpcStatus2;
  10237. ASSERT(*AbortNeeded == FALSE);
  10238. ASSERT(*IoPending == FALSE);
  10239. // if there's a per operation timeout, use the lesser of the operation
  10240. // and connection timeout
  10241. ASSERT(ConnectionTimeout);
  10242. if (Timeout != INFINITE)
  10243. {
  10244. if (Timeout <= ConnectionTimeout)
  10245. {
  10246. dwActualTimeout = Timeout;
  10247. fWaitOnConnectionTimeout = FALSE;
  10248. }
  10249. else
  10250. {
  10251. dwActualTimeout = ConnectionTimeout;
  10252. fWaitOnConnectionTimeout = TRUE;
  10253. }
  10254. }
  10255. else
  10256. {
  10257. // wait on the connection timeout
  10258. dwActualTimeout = ConnectionTimeout;
  10259. fWaitOnConnectionTimeout = TRUE;
  10260. }
  10261. fSetKeepAliveVals = FALSE;
  10262. do
  10263. {
  10264. //
  10265. // Wait for the pending receive to complete
  10266. //
  10267. RpcStatus = UTIL_GetOverlappedHTTP2ResultEx(Connection,
  10268. &Ol.Overlapped,
  10269. Ol.ReceiveOverlapped.hEvent,
  10270. TRUE, // Alertable
  10271. dwActualTimeout);
  10272. if (RpcStatus != RPC_S_OK)
  10273. {
  10274. // if we timed out ...
  10275. if (RpcStatus == RPC_P_TIMEOUT)
  10276. {
  10277. ASSERT(dwActualTimeout != INFINITE);
  10278. // if we waited on the per connection timeout ...
  10279. if (fWaitOnConnectionTimeout)
  10280. {
  10281. ASSERT(ConnectionTimeout != INFINITE);
  10282. if (Timeout == INFINITE)
  10283. {
  10284. // enable keep alives and wait forever
  10285. dwActualTimeout = INFINITE;
  10286. }
  10287. else
  10288. {
  10289. ASSERT(ConnectionTimeout < Timeout);
  10290. // enable keep alives and wait the difference
  10291. dwActualTimeout = Timeout - ConnectionTimeout;
  10292. fWaitOnConnectionTimeout = FALSE;
  10293. }
  10294. // Enable aggressive keepalives on the socket if lower layers
  10295. // support it.
  10296. KATimeout.Milliseconds = ConnectionTimeout;
  10297. RpcStatus2 = SetKeepAliveTimeout (
  10298. TRUE, // TurnOn
  10299. FALSE, // bProtectIO
  10300. tuMilliseconds,
  10301. KATimeout,
  10302. KATimeout.Milliseconds
  10303. );
  10304. if (RpcStatus2 != RPC_S_OK)
  10305. {
  10306. *AbortNeeded = TRUE;
  10307. *IoPending = TRUE;
  10308. goto CleanupAndExit;
  10309. }
  10310. fSetKeepAliveVals = TRUE;
  10311. continue;
  10312. }
  10313. // else we have chosen the per operation timeout and
  10314. // have timed out on that - time to bail out
  10315. }
  10316. // Normal error path
  10317. if ((RpcStatus == RPC_S_CALL_CANCELLED) || (RpcStatus == RPC_P_TIMEOUT))
  10318. {
  10319. if ((RpcStatus == RPC_P_TIMEOUT) && fWaitOnConnectionTimeout)
  10320. {
  10321. RpcStatus = RPC_P_RECEIVE_FAILED;
  10322. }
  10323. *AbortNeeded = TRUE;
  10324. *IoPending = TRUE;
  10325. goto CleanupAndExit;
  10326. }
  10327. *AbortNeeded = TRUE;
  10328. // connection was aborted - no need to turn off keep alives
  10329. goto CleanupAndExit;
  10330. }
  10331. }
  10332. while (RpcStatus == RPC_P_TIMEOUT);
  10333. if (fSetKeepAliveVals)
  10334. {
  10335. // Call completed, clear keep alives. Turning off is a best
  10336. // effort. Ignore failures
  10337. KATimeout.Milliseconds = 0;
  10338. (void) SetKeepAliveTimeout(
  10339. FALSE, // TurnOn
  10340. FALSE, // bProtectIO
  10341. tuMilliseconds,
  10342. KATimeout,
  10343. KATimeout.Milliseconds
  10344. );
  10345. }
  10346. *Buffer = Ol.ReceiveOverlapped.Buffer;
  10347. *BufferLength = Ol.ReceiveOverlapped.BufferLength;
  10348. if (RpcStatus == RPC_S_OK)
  10349. {
  10350. ASSERT(*Buffer != NULL);
  10351. }
  10352. CleanupAndExit:
  10353. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SYNC_RECV, HTTP2LOG_OT_CLIENT_CHANNEL, RpcStatus);
  10354. if (*IoPending == FALSE)
  10355. {
  10356. // consume the event if there will be no wait
  10357. Ol.ReceiveOverlapped.hEvent = NULL;
  10358. }
  10359. return RpcStatus;
  10360. }
  10361. void HTTP2ClientChannel::AbortConnection (
  10362. IN RPC_STATUS AbortReason
  10363. )
  10364. /*++
  10365. Routine Description:
  10366. Aborts the client virtual connection. The only
  10367. difference from HTTP2Channel::AbortConnection
  10368. is that it specifically calls AbortChannels on
  10369. the client virtual connection. This is necessary
  10370. because AbortChannels is not virtual.
  10371. Arguments:
  10372. RpcStatus - the error to abort with
  10373. Return Value:
  10374. --*/
  10375. {
  10376. HTTP2ClientVirtualConnection *VirtualConnection;
  10377. // abort the parent connection
  10378. VirtualConnection = (HTTP2ClientVirtualConnection *)LockParentPointer();
  10379. if (VirtualConnection)
  10380. {
  10381. VirtualConnection->AbortChannels(AbortReason);
  10382. UnlockParentPointer();
  10383. }
  10384. else
  10385. {
  10386. // abort this channel at least
  10387. Abort(AbortReason);
  10388. }
  10389. }
  10390. /*********************************************************************
  10391. HTTP2ClientInChannel
  10392. *********************************************************************/
  10393. RPC_STATUS HTTP2ClientInChannel::ClientOpen (
  10394. IN HTTPResolverHint *Hint,
  10395. IN const char *Verb,
  10396. IN int VerbLength,
  10397. IN BOOL UseWinHttp,
  10398. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  10399. IN ULONG ChosenAuthScheme,
  10400. IN ULONG CallTimeout,
  10401. IN const BYTE *AdditionalData, OPTIONAL
  10402. IN ULONG AdditionalDataLength OPTIONAL
  10403. )
  10404. /*++
  10405. Routine Description:
  10406. Sends the HTTP establishment header on
  10407. the in channel.
  10408. Arguments:
  10409. Hint - the resolver hint
  10410. Verb - the verb to use.
  10411. VerbLength - the length of the verb (in characters, not including
  10412. null terminator).
  10413. UseWinHttp - non-zero if WinHttp needs to be used. 0 otherwise
  10414. HttpCredentials - encrypted transport credentials
  10415. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  10416. CallTimeout - the call timeout for this call
  10417. AdditionalData - additional data to send with the header. Must be set iff
  10418. AdditionalDataLength != 0
  10419. AdditionalDataLength - the length of the additional data to send with the header.
  10420. Must be set iff AdditionalLength != NULL
  10421. Return Value:
  10422. RPC_S_OK or RPC_S_* error
  10423. --*/
  10424. {
  10425. return HTTP2ClientChannel::ClientOpen(Hint,
  10426. Verb,
  10427. VerbLength,
  10428. TRUE, // InChannel
  10429. FALSE, // ReplacementChannel
  10430. UseWinHttp,
  10431. HttpCredentials,
  10432. ChosenAuthScheme,
  10433. GetWinHttpConnection(),
  10434. CallTimeout,
  10435. AdditionalData,
  10436. AdditionalDataLength
  10437. );
  10438. }
  10439. RPC_STATUS HTTP2ClientInChannel::SetKeepAliveTimeout (
  10440. IN BOOL TurnOn,
  10441. IN BOOL bProtectIO,
  10442. IN KEEPALIVE_TIMEOUT_UNITS Units,
  10443. IN OUT KEEPALIVE_TIMEOUT KATime,
  10444. IN ULONG KAInterval OPTIONAL
  10445. )
  10446. /*++
  10447. Routine Description:
  10448. Change the keep alive value on the channel
  10449. Arguments:
  10450. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  10451. are turned off.
  10452. bProtectIO - non-zero if IO needs to be protected against async close
  10453. of the connection.
  10454. Units - in what units is KATime
  10455. KATime - how much to wait before turning on keep alives
  10456. KAInterval - the interval between keep alives
  10457. Return Value:
  10458. RPC_S_OK or other RPC_S_* errors for error.
  10459. May return RPC_P_CHANNEL_NEEDS_RECYCLING - caller needs to handle.
  10460. --*/
  10461. {
  10462. HTTP2SendContext *KeepAliveChangeContext;
  10463. RPC_STATUS RpcStatus;
  10464. BOOL WasChannelRecyclingTriggered;
  10465. ASSERT(Units == tuMilliseconds);
  10466. // HTTP keep alives are heavy weight. Moderate the caller's
  10467. // settings
  10468. if (TurnOn)
  10469. {
  10470. if (KAInterval < MinimumClientSideKeepAliveInterval)
  10471. KAInterval = MinimumClientSideKeepAliveInterval;
  10472. }
  10473. else
  10474. {
  10475. KAInterval = 0;
  10476. }
  10477. // tell the proxy to change it's keepalives and then
  10478. // ask our ping originator to change its keepalives as well
  10479. KeepAliveChangeContext = AllocateAndInitializeKeepAliveChangePacket (KAInterval);
  10480. if (KeepAliveChangeContext == NULL)
  10481. return RPC_S_OUT_OF_MEMORY;
  10482. RpcStatus = Send(KeepAliveChangeContext);
  10483. WasChannelRecyclingTriggered = FALSE;
  10484. if (RpcStatus != RPC_S_OK)
  10485. {
  10486. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  10487. WasChannelRecyclingTriggered = TRUE;
  10488. else
  10489. {
  10490. FreeRTSPacket(KeepAliveChangeContext);
  10491. return RpcStatus;
  10492. }
  10493. }
  10494. // get into submission context
  10495. RpcStatus = BeginSimpleSubmitAsync();
  10496. if (RpcStatus != RPC_S_OK)
  10497. return RpcStatus;
  10498. // ask our ping channel to change as well
  10499. RpcStatus = GetPingOriginatorChannel()->SetKeepAliveTimeout (
  10500. TurnOn,
  10501. bProtectIO,
  10502. Units,
  10503. KATime,
  10504. KAInterval
  10505. );
  10506. FinishSubmitAsync();
  10507. // if we failed for other reasons or channel recycling was not triggered
  10508. // at all, return the current status
  10509. if ((WasChannelRecyclingTriggered == FALSE) || (RpcStatus != RPC_S_OK))
  10510. return RpcStatus;
  10511. else
  10512. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  10513. }
  10514. /*********************************************************************
  10515. HTTP2ClientOutChannel
  10516. *********************************************************************/
  10517. RPC_STATUS HTTP2ClientOutChannel::ClientOpen (
  10518. IN HTTPResolverHint *Hint,
  10519. IN const char *Verb,
  10520. IN int VerbLength,
  10521. IN BOOL ReplacementChannel,
  10522. IN BOOL UseWinHttp,
  10523. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  10524. IN ULONG ChosenAuthScheme,
  10525. IN ULONG CallTimeout,
  10526. IN const BYTE *AdditionalData, OPTIONAL
  10527. IN ULONG AdditionalDataLength OPTIONAL
  10528. )
  10529. /*++
  10530. Routine Description:
  10531. Sends the HTTP establishment header on
  10532. the out channel.
  10533. Arguments:
  10534. Hint - the resolver hint
  10535. Verb - the verb to use.
  10536. VerbLength - the length of the verb (in characters, not including
  10537. null terminator).
  10538. ReplacementChannel - non-zero if this is a replacement channel.
  10539. Zero if it is not.
  10540. UseWinHttp - non-zero if WinHttp needs to be used. 0 otherwise
  10541. HttpCredentials - encrypted transport credentials
  10542. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  10543. CallTimeout - the call timeout for this call.
  10544. AdditionalData - additional data to send with the header. Must be set iff
  10545. AdditionalDataLength != 0
  10546. AdditionalDataLength - the length of the additional data to send with the header.
  10547. Must be set iff AdditionalLength != NULL
  10548. Return Value:
  10549. RPC_S_OK or RPC_S_* error
  10550. --*/
  10551. {
  10552. return HTTP2ClientChannel::ClientOpen(Hint,
  10553. Verb,
  10554. VerbLength,
  10555. FALSE, // InChannel
  10556. ReplacementChannel,
  10557. UseWinHttp,
  10558. HttpCredentials,
  10559. ChosenAuthScheme,
  10560. GetWinHttpConnection(),
  10561. CallTimeout,
  10562. AdditionalData,
  10563. AdditionalDataLength
  10564. );
  10565. }
  10566. RPC_STATUS HTTP2ClientOutChannel::ForwardFlowControlAck (
  10567. IN ULONG BytesReceivedForAck,
  10568. IN ULONG WindowForAck
  10569. )
  10570. /*++
  10571. Routine Description:
  10572. Forwards a flow control ack to the out proxy through the in proxy
  10573. Arguments:
  10574. BytesReceivedForAck - the bytes received when the ACK was issued
  10575. WindowForAck - the free window when the ACK was issued.
  10576. Return Value:
  10577. RPC_S_OK or RPC_S_*
  10578. Notes:
  10579. Must be called from neutral context only.
  10580. --*/
  10581. {
  10582. RPC_STATUS RpcStatus;
  10583. RpcStatus = ForwardFlowControlAckOnDefaultChannel(TRUE, // IsInChannel
  10584. fdOutProxy,
  10585. BytesReceivedForAck,
  10586. WindowForAck
  10587. );
  10588. RpcStatus = HandleSendResultFromNeutralContext(RpcStatus);
  10589. return RpcStatus;
  10590. }
  10591. RPC_STATUS HTTP2ClientOutChannel::SetKeepAliveTimeout (
  10592. IN BOOL TurnOn,
  10593. IN BOOL bProtectIO,
  10594. IN KEEPALIVE_TIMEOUT_UNITS Units,
  10595. IN OUT KEEPALIVE_TIMEOUT KATime,
  10596. IN ULONG KAInterval OPTIONAL
  10597. )
  10598. /*++
  10599. Routine Description:
  10600. Change the keep alive value on the channel
  10601. Arguments:
  10602. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  10603. are turned off.
  10604. bProtectIO - non-zero if IO needs to be protected against async close
  10605. of the connection.
  10606. Units - in what units is KATime
  10607. KATime - how much to wait before turning on keep alives
  10608. KAInterval - the interval between keep alives
  10609. Return Value:
  10610. RPC_S_OK or other RPC_S_* errors for error
  10611. --*/
  10612. {
  10613. HTTP2ClientVirtualConnection *VirtualConnection;
  10614. RPC_STATUS RpcStatus;
  10615. // turn around the request through the connection
  10616. VirtualConnection = LockParentPointer();
  10617. if (VirtualConnection == NULL)
  10618. return RPC_P_CONNECTION_SHUTDOWN;
  10619. RpcStatus = VirtualConnection->TurnOnOffKeepAlives(
  10620. TurnOn,
  10621. bProtectIO,
  10622. TRUE, // IsFromUpcall
  10623. Units,
  10624. KATime,
  10625. KAInterval
  10626. );
  10627. UnlockParentPointer();
  10628. return RpcStatus;
  10629. }
  10630. /*********************************************************************
  10631. HTTP2ClientVirtualConnection
  10632. *********************************************************************/
  10633. RPC_STATUS HTTP2ClientVirtualConnection::ClientOpen (
  10634. IN HTTPResolverHint *Hint,
  10635. IN BOOL HintWasInitialized,
  10636. IN UINT ConnTimeout,
  10637. IN ULONG CallTimeout
  10638. )
  10639. /*++
  10640. Routine Description:
  10641. Opens a client side virtual connection.
  10642. Arguments:
  10643. Hint - the resolver hint
  10644. HintWasInitialized - the hint was initialized on input.
  10645. ConnTimeout - connection timeout
  10646. CallTimeout - operation timeout
  10647. Return Value:
  10648. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10649. --*/
  10650. {
  10651. return ClientOpenInternal (
  10652. Hint,
  10653. HintWasInitialized,
  10654. ConnTimeout,
  10655. CallTimeout,
  10656. TRUE, // OpenInChannel
  10657. TRUE, // OpenOutChannel
  10658. FALSE, // IsReplacementChannel
  10659. FALSE // IsFromUpcall
  10660. );
  10661. }
  10662. RPC_STATUS HTTP2ClientVirtualConnection::SendComplete (
  10663. IN RPC_STATUS EventStatus,
  10664. IN OUT HTTP2SendContext *SendContext,
  10665. IN int ChannelId
  10666. )
  10667. /*++
  10668. Routine Description:
  10669. Called by lower layers to indicate send complete.
  10670. Arguments:
  10671. EventStatus - status of the operation
  10672. SendContext - the context for the send complete
  10673. ChannelId - which channel completed the operation
  10674. Return Value:
  10675. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  10676. be hidden from the runtime.
  10677. RPC_S_OK if the packet was processed successfully.
  10678. RPC_S_* error if there was an error while processing the
  10679. packet.
  10680. --*/
  10681. {
  10682. HTTP2TrafficType TrafficType;
  10683. VerifyValidChannelId(ChannelId);
  10684. if (EventStatus == RPC_S_OK)
  10685. {
  10686. // successful sends are always no-ops on the
  10687. // client. Just cleanup if necessary and
  10688. // return
  10689. if (SendContext->TrafficType == http2ttRTS)
  10690. {
  10691. FreeSendContextAndPossiblyData(SendContext);
  10692. return RPC_P_PACKET_CONSUMED;
  10693. }
  10694. else
  10695. return RPC_S_OK;
  10696. }
  10697. // we know the send failed
  10698. if (IsDefaultInChannel(ChannelId) || IsDefaultOutChannel(ChannelId))
  10699. {
  10700. // on a default channel such error is fatal
  10701. AbortChannels(EventStatus);
  10702. if (SendContext->TrafficType == http2ttRTS)
  10703. {
  10704. FreeSendContextAndPossiblyData(SendContext);
  10705. return RPC_P_PACKET_CONSUMED;
  10706. }
  10707. ASSERT(SendContext->TrafficType == http2ttData);
  10708. return EventStatus;
  10709. }
  10710. else
  10711. {
  10712. // all data sends go on default channels. RTS sends
  10713. // may go either way. If this is RTS, this is fatal.
  10714. // Otherwise, ignore.
  10715. if (SendContext->TrafficType == http2ttRTS)
  10716. {
  10717. FreeSendContextAndPossiblyData(SendContext);
  10718. AbortChannels(EventStatus);
  10719. return RPC_P_PACKET_CONSUMED;
  10720. }
  10721. else
  10722. return RPC_S_OK;
  10723. }
  10724. }
  10725. RPC_STATUS HTTP2ClientVirtualConnection::ReceiveComplete (
  10726. IN RPC_STATUS EventStatus,
  10727. IN BYTE *Buffer,
  10728. IN UINT BufferLength,
  10729. IN int ChannelId
  10730. )
  10731. /*++
  10732. Routine Description:
  10733. Called by lower layers to indicate receive complete
  10734. Arguments:
  10735. EventStatus - RPC_S_OK for success or RPC_S_* for error
  10736. Buffer - buffer received
  10737. BufferLength - length of buffer received
  10738. ChannelId - which channel completed the operation
  10739. Return Value:
  10740. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  10741. be hidden from the runtime.
  10742. RPC_P_ABORT_NEEDED - if the channel needs to be aborted but
  10743. couldn't be aborted in this function because it was detached.
  10744. After aborting, the semantics is same as RPC_P_PACKET_CONSUMED.
  10745. RPC_S_OK if the packet was processed successfully.
  10746. RPC_S_* error if there was an error while processing the
  10747. packet.
  10748. --*/
  10749. {
  10750. RPC_STATUS RpcStatus;
  10751. ULONG ProxyConnectionTimeout;
  10752. BOOL BufferFreed = FALSE;
  10753. BOOL WakeOpenThread;
  10754. HTTP2ClientInChannel *InChannel;
  10755. HTTP2ClientOutChannel *OutChannel;
  10756. HTTP2ClientOutChannel *OutChannel2;
  10757. HTTP2ClientInChannel *NewInChannel;
  10758. HTTP2ChannelPointer *ChannelPtr;
  10759. HTTP2ChannelPointer *NewChannelPtr;
  10760. LIST_ENTRY NewBufferHead;
  10761. LIST_ENTRY *CurrentListEntry;
  10762. LIST_ENTRY *PrevListEntry;
  10763. HTTP2SendContext *QueuedSendContext;
  10764. BOOL MutexReleased;
  10765. HTTP2SendContext *A5Context; // may be D2/A5 or D3/A5
  10766. HTTP2SendContext *D4_A7Context;
  10767. HTTP2SendContext *PingContext;
  10768. BOOL IsD2_A4;
  10769. HTTP2ClientOpenedPacketType ClientPacketType;
  10770. BOOL DataReceivePosted;
  10771. HTTP2StateValues NewState;
  10772. HTTP2StateValues ExpectedState;
  10773. ULONG BytesReceivedForAck;
  10774. ULONG WindowForAck;
  10775. HTTP2Cookie CookieForChannel;
  10776. ULONG InProxyReceiveWindow;
  10777. BOOL UseWinHttp;
  10778. KEEPALIVE_TIMEOUT KATimeout;
  10779. VerifyValidChannelId(ChannelId);
  10780. if (
  10781. (InChannelState.State == http2svSearchProxy)
  10782. &&
  10783. (
  10784. (EventStatus != RPC_S_OK)
  10785. ||
  10786. IsEchoPacket(Buffer, BufferLength)
  10787. )
  10788. )
  10789. {
  10790. InChannelState.Mutex.Request();
  10791. if (InChannelState.State == http2svSearchProxy)
  10792. {
  10793. InChannelState.Mutex.Clear();
  10794. if (IsInChannel(ChannelId))
  10795. {
  10796. InOpenStatus = EventStatus;
  10797. }
  10798. else
  10799. {
  10800. OutOpenStatus = EventStatus;
  10801. }
  10802. // we won the race. Wake up the open thread
  10803. WakeOpenThread = TRUE;
  10804. RpcStatus = RPC_P_PACKET_CONSUMED;
  10805. goto CleanupAndExit;
  10806. }
  10807. InChannelState.Mutex.Clear();
  10808. }
  10809. WakeOpenThread = FALSE;
  10810. if (IsInChannel(ChannelId))
  10811. {
  10812. if (EventStatus != RPC_P_AUTH_NEEDED)
  10813. {
  10814. // we shouldn't really be receiving stuff on the in channel
  10815. // unless there is an error
  10816. if (EventStatus != RPC_S_OK)
  10817. {
  10818. if (IsDefaultInChannel(ChannelId) == FALSE)
  10819. {
  10820. InChannelState.Mutex.Request();
  10821. if (InChannelState.State == http2svOpened)
  10822. {
  10823. // close on the non-default channel in open
  10824. // state is not an error for the connection
  10825. // just abort the channel in question
  10826. InChannelState.Mutex.Clear();
  10827. ChannelPtr = GetChannelPointerFromId(ChannelId);
  10828. InChannel = (HTTP2ClientInChannel *)ChannelPtr->LockChannelPointer();
  10829. if (InChannel)
  10830. {
  10831. InChannel->Abort(EventStatus);
  10832. ChannelPtr->UnlockChannelPointer();
  10833. RpcStatus = RPC_P_PACKET_CONSUMED;
  10834. }
  10835. else
  10836. RpcStatus = RPC_P_ABORT_NEEDED;
  10837. BufferFreed = TRUE;
  10838. return RpcStatus;
  10839. }
  10840. else
  10841. InChannelState.Mutex.Clear();
  10842. }
  10843. RpcStatus = EventStatus;
  10844. // in failed receives, we don't own the buffer
  10845. BufferFreed = TRUE;
  10846. }
  10847. else
  10848. {
  10849. if (IsEchoPacket(Buffer, BufferLength))
  10850. {
  10851. InOpenStatus = EventStatus;
  10852. WakeOpenThread = TRUE;
  10853. RpcStatus = RPC_P_PACKET_CONSUMED;
  10854. goto CleanupAndExit;
  10855. }
  10856. RpcStatus = RPC_S_PROTOCOL_ERROR;
  10857. }
  10858. AbortChannels(RpcStatus);
  10859. }
  10860. else
  10861. {
  10862. // turn around the error code and fall through
  10863. RpcStatus = EventStatus;
  10864. }
  10865. // the runtime never posted a receive on the in
  10866. // channel. Don't let it see the packet
  10867. InOpenStatus = RpcStatus;
  10868. WakeOpenThread = TRUE;
  10869. RpcStatus = RPC_P_PACKET_CONSUMED;
  10870. }
  10871. else
  10872. {
  10873. // this is an out channel
  10874. if (EventStatus != RPC_S_OK)
  10875. {
  10876. if (EventStatus != RPC_P_AUTH_NEEDED)
  10877. {
  10878. AbortChannels(EventStatus);
  10879. RpcStatus = EventStatus;
  10880. if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  10881. RpcStatus = RPC_P_RECEIVE_FAILED;
  10882. OutOpenStatus = RpcStatus;
  10883. }
  10884. else
  10885. {
  10886. OutOpenStatus = EventStatus;
  10887. RpcStatus = RPC_P_RECEIVE_FAILED;
  10888. }
  10889. WakeOpenThread = TRUE;
  10890. // in failed receives we don't own the buffer
  10891. BufferFreed = TRUE;
  10892. }
  10893. else
  10894. {
  10895. // verify state and act upon it if RTS
  10896. // for data we don't care
  10897. if (IsRTSPacket(Buffer))
  10898. {
  10899. if (IsOtherCmdPacket(Buffer, BufferLength))
  10900. {
  10901. // the only cmd packet we expect is flow control ack
  10902. // try to interpret it as such
  10903. RpcStatus = ParseAndFreeFlowControlAckPacketWithDestination (
  10904. Buffer,
  10905. BufferLength,
  10906. fdClient,
  10907. &BytesReceivedForAck,
  10908. &WindowForAck,
  10909. &CookieForChannel
  10910. );
  10911. BufferFreed = TRUE;
  10912. if (RpcStatus == RPC_S_OK)
  10913. {
  10914. // notify the flow control sender about the ack
  10915. InChannel = (HTTP2ClientInChannel *)MapCookieToChannelPointer(
  10916. &CookieForChannel,
  10917. &ChannelPtr
  10918. );
  10919. if (InChannel)
  10920. {
  10921. RpcStatus = InChannel->FlowControlAckNotify(BytesReceivedForAck,
  10922. WindowForAck
  10923. );
  10924. ChannelPtr->UnlockChannelPointer();
  10925. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  10926. TRUE // IsFromUpcall
  10927. );
  10928. }
  10929. if (RpcStatus == RPC_S_OK)
  10930. {
  10931. // post another receive
  10932. RpcStatus = PostReceiveOnChannel (GetChannelPointerFromId(ChannelId),
  10933. http2ttRTS
  10934. );
  10935. }
  10936. }
  10937. if (RpcStatus != RPC_S_OK)
  10938. {
  10939. AbortChannels(RpcStatus);
  10940. OutOpenStatus = RpcStatus;
  10941. WakeOpenThread = TRUE;
  10942. }
  10943. // This is an RTS packet - consume it
  10944. RpcStatus = RPC_P_PACKET_CONSUMED;
  10945. goto CleanupAndExit;
  10946. }
  10947. else if (IsEchoPacket(Buffer, BufferLength))
  10948. {
  10949. OutOpenStatus = EventStatus;
  10950. WakeOpenThread = TRUE;
  10951. RpcStatus = RPC_P_PACKET_CONSUMED;
  10952. goto CleanupAndExit;
  10953. }
  10954. RpcStatus = HTTPTransInfo->CreateThread();
  10955. if (RpcStatus != RPC_S_OK)
  10956. {
  10957. AbortChannels(RpcStatus);
  10958. // This is an RTS packet - consume it
  10959. RpcFreeBuffer(Buffer);
  10960. BufferFreed = TRUE;
  10961. OutOpenStatus = RpcStatus;
  10962. WakeOpenThread = TRUE;
  10963. RpcStatus = RPC_P_PACKET_CONSUMED;
  10964. goto CleanupAndExit;
  10965. }
  10966. MutexReleased = FALSE;
  10967. InChannelState.Mutex.Request();
  10968. switch (InChannelState.State)
  10969. {
  10970. case http2svA3W:
  10971. RpcStatus = ParseAndFreeD1_A3(Buffer,
  10972. BufferLength,
  10973. &ProxyConnectionTimeout
  10974. );
  10975. // we don't really do anything with the ProxyConnectionTimeout - it's
  10976. // for debugging purposes only
  10977. BufferFreed = TRUE;
  10978. if (RpcStatus == RPC_S_OK)
  10979. {
  10980. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRTS);
  10981. if (RpcStatus == RPC_S_OK)
  10982. {
  10983. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svC2W, 1, 0);
  10984. InChannelState.State = http2svC2W;
  10985. RpcStatus = RPC_P_PACKET_CONSUMED;
  10986. }
  10987. else
  10988. OutOpenStatus = RpcStatus;
  10989. }
  10990. break;
  10991. case http2svC2W:
  10992. RpcStatus = ParseAndFreeD1_C2(Buffer,
  10993. BufferLength,
  10994. &ProtocolVersion,
  10995. &InProxyReceiveWindow,
  10996. &InProxyConnectionTimeout
  10997. );
  10998. BufferFreed = TRUE;
  10999. if (RpcStatus == RPC_S_OK)
  11000. {
  11001. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRTS);
  11002. if (RpcStatus == RPC_S_OK)
  11003. {
  11004. // Set the in proxy timeout to the channel
  11005. InChannel = LockDefaultInChannel(&ChannelPtr);
  11006. if (InChannel != NULL)
  11007. {
  11008. InChannel->SetPeerReceiveWindow(InProxyReceiveWindow);
  11009. RpcStatus = InChannel->SetConnectionTimeout(InProxyConnectionTimeout);
  11010. ChannelPtr->UnlockChannelPointer();
  11011. }
  11012. else
  11013. RpcStatus = RPC_P_CONNECTION_CLOSED;
  11014. if (RpcStatus != RPC_S_OK)
  11015. {
  11016. AbortChannels(RpcStatus);
  11017. OutOpenStatus = RpcStatus;
  11018. break;
  11019. }
  11020. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  11021. InChannelState.State = http2svOpened;
  11022. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  11023. OutChannelState.State = http2svOpened;
  11024. InOpenStatus = OutOpenStatus = RPC_S_OK;
  11025. SetClientOpenInEvent();
  11026. RpcStatus = RPC_P_PACKET_CONSUMED;
  11027. }
  11028. }
  11029. break;
  11030. default:
  11031. // all the opened states are handled here
  11032. ASSERT((InChannelState.State == http2svOpened)
  11033. || (InChannelState.State == http2svOpened_A4W) );
  11034. ASSERT((OutChannelState.State == http2svOpened)
  11035. || (OutChannelState.State == http2svOpened_A6W)
  11036. || (OutChannelState.State == http2svOpened_A10W)
  11037. || (OutChannelState.State == http2svOpened_B3W) );
  11038. RpcStatus = GetClientOpenedPacketType (Buffer,
  11039. BufferLength,
  11040. &ClientPacketType
  11041. );
  11042. if (RpcStatus != RPC_S_OK)
  11043. {
  11044. AbortChannels(RpcStatus);
  11045. break;
  11046. }
  11047. switch (ClientPacketType)
  11048. {
  11049. case http2coptD2_A4:
  11050. case http2coptD3_A4:
  11051. // in channel must be in Opened_A4W
  11052. // out channel can be in any state
  11053. ASSERT(InChannelState.State == http2svOpened_A4W);
  11054. InChannelState.Mutex.Clear();
  11055. MutexReleased = TRUE;
  11056. IsD2_A4 = IsD2_A4OrD3_A4(Buffer,
  11057. BufferLength
  11058. );
  11059. if (IsD2_A4)
  11060. {
  11061. RpcStatus = ParseAndFreeD2_A4(Buffer,
  11062. BufferLength,
  11063. fdClient,
  11064. &ProtocolVersion,
  11065. &InProxyReceiveWindow,
  11066. &InProxyConnectionTimeout
  11067. );
  11068. }
  11069. else
  11070. {
  11071. // This must be a D3/A4
  11072. RpcStatus = ParseAndFreeD3_A4 (Buffer,
  11073. BufferLength
  11074. );
  11075. }
  11076. BufferFreed = TRUE;
  11077. if (RpcStatus != RPC_S_OK)
  11078. {
  11079. AbortChannels(RpcStatus);
  11080. break;
  11081. }
  11082. RpcStatus = PostReceiveOnChannel(&OutChannels[DefaultOutChannelSelector],
  11083. http2ttRTS);
  11084. if (RpcStatus != RPC_S_OK)
  11085. {
  11086. AbortChannels(RpcStatus);
  11087. break;
  11088. }
  11089. // lock the old channel
  11090. InChannel = LockDefaultInChannel(&ChannelPtr);
  11091. if (InChannel == NULL)
  11092. {
  11093. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11094. RpcStatus = RPC_P_PACKET_CONSUMED;
  11095. break;
  11096. }
  11097. if (IsD2_A4 == FALSE)
  11098. {
  11099. // capture the receive window from the old channel.
  11100. // We know the proxy is the same so the window must be
  11101. // the same as well
  11102. InProxyReceiveWindow = InChannel->GetPeerReceiveWindow();
  11103. }
  11104. // switch channels (new channel is still plugged)
  11105. SwitchDefaultInChannelSelector();
  11106. // wait for everybody that is in the process of using
  11107. // the old channel to get out
  11108. InChannel->DrainPendingSubmissions();
  11109. // leave 1 for our lock
  11110. ChannelPtr->DrainPendingLocks(1);
  11111. // lock new channel (by now it is default)
  11112. NewInChannel = LockDefaultInChannel(&NewChannelPtr);
  11113. if (NewInChannel == NULL)
  11114. {
  11115. ChannelPtr->UnlockChannelPointer();
  11116. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11117. RpcStatus = RPC_P_PACKET_CONSUMED;
  11118. break;
  11119. }
  11120. NewInChannel->SetPeerReceiveWindow(InProxyReceiveWindow);
  11121. // Set the in proxy timeout to the new channel
  11122. RpcStatus = NewInChannel->SetConnectionTimeout(InProxyConnectionTimeout);
  11123. if (RpcStatus != RPC_S_OK)
  11124. {
  11125. NewChannelPtr->UnlockChannelPointer();
  11126. ChannelPtr->UnlockChannelPointer();
  11127. AbortChannels(RpcStatus);
  11128. RpcStatus = RPC_P_PACKET_CONSUMED;
  11129. break;
  11130. }
  11131. // if old flow control channel was queuing, grab all its buffers
  11132. // We must do this before the channel data originator to make sure
  11133. // the buffers end up behind the ones from the channel data
  11134. // originator
  11135. RpcpInitializeListHead(&NewBufferHead);
  11136. InChannel->GetFlowControlSenderBufferQueue(&NewBufferHead);
  11137. AddBufferQueueToChannel(&NewBufferHead, NewInChannel);
  11138. // GetChannelOriginatorBufferQueue can be called in submission
  11139. // context only. Get into submission context
  11140. RpcStatus = InChannel->BeginSimpleSubmitAsync();
  11141. if (RpcStatus != RPC_S_OK)
  11142. {
  11143. NewChannelPtr->UnlockChannelPointer();
  11144. ChannelPtr->UnlockChannelPointer();
  11145. AbortChannels(RpcStatus);
  11146. RpcStatus = RPC_P_PACKET_CONSUMED;
  11147. break;
  11148. }
  11149. // if old channel channel data originator was queuing, grab all its buffers
  11150. RpcpInitializeListHead(&NewBufferHead);
  11151. InChannel->GetChannelOriginatorBufferQueue(&NewBufferHead);
  11152. InChannel->FinishSubmitAsync();
  11153. AddBufferQueueToChannel(&NewBufferHead, NewInChannel);
  11154. InChannelState.Mutex.Request();
  11155. // move channel state to opened
  11156. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  11157. InChannelState.State = http2svOpened;
  11158. InChannelState.Mutex.Clear();
  11159. if (IsD2_A4)
  11160. {
  11161. // register the last packet to send with the old channel
  11162. A5Context = AllocateAndInitializeD2_A5 (
  11163. &InChannelCookies[DefaultInChannelSelector]
  11164. );
  11165. }
  11166. else
  11167. {
  11168. A5Context = AllocateAndInitializeD3_A5 (
  11169. &InChannelCookies[DefaultInChannelSelector]
  11170. );
  11171. }
  11172. if (A5Context == NULL)
  11173. {
  11174. ChannelPtr->UnlockChannelPointer();
  11175. NewChannelPtr->UnlockChannelPointer();
  11176. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11177. RpcStatus = RPC_P_PACKET_CONSUMED;
  11178. break;
  11179. }
  11180. // make sure the packet is sent last
  11181. RpcStatus = InChannel->Send(A5Context);
  11182. if (RpcStatus == RPC_S_OK)
  11183. {
  11184. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  11185. if (UseWinHttp)
  11186. {
  11187. InChannel->DisablePings();
  11188. RpcStatus = InChannel->Receive(http2ttRaw);
  11189. }
  11190. }
  11191. else
  11192. {
  11193. FreeRTSPacket(A5Context);
  11194. }
  11195. if (RpcStatus != RPC_S_OK)
  11196. {
  11197. ChannelPtr->UnlockChannelPointer();
  11198. NewChannelPtr->UnlockChannelPointer();
  11199. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11200. RpcStatus = RPC_P_PACKET_CONSUMED;
  11201. break;
  11202. }
  11203. // D2_A5 was sent. We must switch the
  11204. // default loopback and detach the channel.
  11205. // Note that we don't abort the channel - we
  11206. // just release the lifetime reference
  11207. // When the proxy closes the connection, then
  11208. // we will abort.
  11209. SwitchDefaultLoopbackChannelSelector();
  11210. ChannelPtr->UnlockChannelPointer();
  11211. ChannelPtr->FreeChannelPointer(
  11212. TRUE, // DrainUpcalls
  11213. FALSE, // CalledFromUpcallContext
  11214. FALSE, // Abort
  11215. RPC_S_OK
  11216. );
  11217. RpcStatus = NewInChannel->Unplug();
  11218. if (RpcStatus != RPC_S_OK)
  11219. {
  11220. NewChannelPtr->UnlockChannelPointer();
  11221. AbortChannels(RpcStatus);
  11222. RpcStatus = RPC_P_PACKET_CONSUMED;
  11223. break;
  11224. }
  11225. NewChannelPtr->UnlockChannelPointer();
  11226. RpcStatus = RPC_P_PACKET_CONSUMED;
  11227. break;
  11228. case http2coptD4_A2:
  11229. // in channel can be in any opened state
  11230. // out channel must be in http2svOpened
  11231. ASSERT(OutChannelState.State == http2svOpened);
  11232. if (OutChannelState.State != http2svOpened)
  11233. {
  11234. AbortChannels(RpcStatus);
  11235. RpcStatus = RPC_P_PACKET_CONSUMED;
  11236. break;
  11237. }
  11238. InChannelState.Mutex.Clear();
  11239. MutexReleased = TRUE;
  11240. RpcStatus = ParseAndFreeD4_A2(Buffer,
  11241. BufferLength
  11242. );
  11243. BufferFreed = TRUE;
  11244. if (RpcStatus != RPC_S_OK)
  11245. {
  11246. AbortChannels(RpcStatus);
  11247. RpcStatus = RPC_P_PACKET_CONSUMED;
  11248. break;
  11249. }
  11250. RpcStatus = OpenReplacementOutChannel();
  11251. if (RpcStatus != RPC_S_OK)
  11252. {
  11253. AbortChannels(RpcStatus);
  11254. RpcStatus = RPC_P_PACKET_CONSUMED;
  11255. break;
  11256. }
  11257. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  11258. http2ttRTS);
  11259. if (RpcStatus != RPC_S_OK)
  11260. AbortChannels(RpcStatus);
  11261. RpcStatus = RPC_P_PACKET_CONSUMED;
  11262. break;
  11263. case http2coptD4_A6:
  11264. case http2coptD5_A6:
  11265. // in channel can be in any opened state
  11266. // out channel must be in http2svOpened_A6W
  11267. ASSERT(OutChannelState.State == http2svOpened_A6W);
  11268. if (OutChannelState.State != http2svOpened_A6W)
  11269. {
  11270. AbortChannels(RpcStatus);
  11271. RpcStatus = RPC_P_PACKET_CONSUMED;
  11272. break;
  11273. }
  11274. if (ClientPacketType == http2coptD4_A6)
  11275. NewState = http2svOpened_A10W;
  11276. else
  11277. NewState = http2svOpened_B3W;
  11278. // move channel state to new state
  11279. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, NewState, 1, 0);
  11280. OutChannelState.State = NewState;
  11281. InChannelState.Mutex.Clear();
  11282. MutexReleased = TRUE;
  11283. if (ClientPacketType == http2coptD4_A6)
  11284. {
  11285. RpcStatus = ParseAndFreeD4_A6 (Buffer,
  11286. BufferLength,
  11287. fdClient,
  11288. &ProtocolVersion,
  11289. &ProxyConnectionTimeout
  11290. );
  11291. // we don't really do anything with ProxyConnectionTimeout. That's
  11292. // ok. It's there mostly for debugging.
  11293. }
  11294. else
  11295. {
  11296. RpcStatus = ParseAndFreeD5_A6 (Buffer,
  11297. BufferLength,
  11298. fdClient
  11299. );
  11300. }
  11301. BufferFreed = TRUE;
  11302. if (RpcStatus != RPC_S_OK)
  11303. {
  11304. AbortChannels(RpcStatus);
  11305. RpcStatus = RPC_P_PACKET_CONSUMED;
  11306. break;
  11307. }
  11308. if (ClientPacketType == http2coptD5_A6)
  11309. {
  11310. // in the D5 case, we won't send A11. Since
  11311. // some proxies are picky about sending all
  11312. // the declared data before allowing receiving
  11313. // data to come in, we need to send an empty packet
  11314. // of the necessary size to keep the proxy happy.
  11315. PingContext = AllocateAndInitializePingPacketWithSize (
  11316. GetD4_A11TotalLength()
  11317. );
  11318. if (PingContext == NULL)
  11319. {
  11320. AbortChannels(RPC_S_OUT_OF_MEMORY);
  11321. RpcStatus = RPC_P_PACKET_CONSUMED;
  11322. break;
  11323. }
  11324. RpcStatus = SendTrafficOnChannel(
  11325. &OutChannels[GetNonDefaultOutChannelSelector()],
  11326. PingContext
  11327. );
  11328. if (RpcStatus != RPC_S_OK)
  11329. {
  11330. FreeRTSPacket(PingContext);
  11331. AbortChannels(RpcStatus);
  11332. break;
  11333. }
  11334. }
  11335. D4_A7Context = AllocateAndInitializeD4_A7 (
  11336. fdServer,
  11337. &OutChannelCookies[GetNonDefaultOutChannelSelector()]
  11338. );
  11339. if (D4_A7Context == NULL)
  11340. {
  11341. AbortChannels(RPC_S_OUT_OF_MEMORY);
  11342. RpcStatus = RPC_P_PACKET_CONSUMED;
  11343. break;
  11344. }
  11345. RpcStatus = SendTrafficOnDefaultChannel(TRUE, //IsInChannel
  11346. D4_A7Context
  11347. );
  11348. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  11349. TRUE // IsFromUpcall
  11350. );
  11351. if (RpcStatus != RPC_S_OK)
  11352. {
  11353. FreeRTSPacket(D4_A7Context);
  11354. AbortChannels(RpcStatus);
  11355. break;
  11356. }
  11357. RpcStatus = PostReceiveOnDefaultChannel (FALSE, // IsInChannel
  11358. http2ttRTS);
  11359. if (RpcStatus != RPC_S_OK)
  11360. AbortChannels(RpcStatus);
  11361. RpcStatus = RPC_P_PACKET_CONSUMED;
  11362. break;
  11363. case http2coptD4_A10:
  11364. case http2coptD5_B3:
  11365. // in channel can be in any opened state
  11366. if (ClientPacketType == http2coptD4_A10)
  11367. {
  11368. // out channel must be in http2svOpened_A10W
  11369. ASSERT(OutChannelState.State == http2svOpened_A10W);
  11370. if (OutChannelState.State != http2svOpened_A10W)
  11371. {
  11372. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11373. RpcStatus = RPC_P_PACKET_CONSUMED;
  11374. break;
  11375. }
  11376. InChannelState.Mutex.Clear();
  11377. MutexReleased = TRUE;
  11378. RpcStatus = ParseD4_A10 (Buffer,
  11379. BufferLength
  11380. );
  11381. if (RpcStatus != RPC_S_OK)
  11382. {
  11383. AbortChannels(RpcStatus);
  11384. RpcStatus = RPC_P_PACKET_CONSUMED;
  11385. break;
  11386. }
  11387. }
  11388. else
  11389. {
  11390. // out channel must be in http2svOpened_B3W
  11391. ASSERT(OutChannelState.State == http2svOpened_B3W);
  11392. if (OutChannelState.State != http2svOpened_B3W)
  11393. {
  11394. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11395. RpcStatus = RPC_P_PACKET_CONSUMED;
  11396. break;
  11397. }
  11398. InChannelState.Mutex.Clear();
  11399. MutexReleased = TRUE;
  11400. RpcStatus = ParseAndFreeD5_B3 (Buffer,
  11401. BufferLength
  11402. );
  11403. BufferFreed = TRUE;
  11404. if (RpcStatus != RPC_S_OK)
  11405. {
  11406. AbortChannels(RpcStatus);
  11407. RpcStatus = RPC_P_PACKET_CONSUMED;
  11408. break;
  11409. }
  11410. }
  11411. ChannelPtr = GetChannelPointerFromId(ChannelId);
  11412. OutChannel = (HTTP2ClientOutChannel *)ChannelPtr->LockChannelPointer();
  11413. if (OutChannel == NULL)
  11414. {
  11415. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11416. RpcStatus = RPC_P_PACKET_CONSUMED;
  11417. break;
  11418. }
  11419. NewChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  11420. OutChannel2 = (HTTP2ClientOutChannel *)NewChannelPtr->LockChannelPointer ();
  11421. if (OutChannel2 == NULL)
  11422. {
  11423. ChannelPtr->UnlockChannelPointer();
  11424. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11425. RpcStatus = RPC_P_PACKET_CONSUMED;
  11426. break;
  11427. }
  11428. OutChannel2->BlockDataReceives();
  11429. // we're done with this channel. We want to switch
  11430. // channels and destroy
  11431. // and detach the channel.
  11432. // In the D5 case we can't switch earlier, because we
  11433. // have a race condition where folks may receive data
  11434. // on the new channel before they have drained the old,
  11435. // which may result in out-of-order delivery. Since
  11436. // data receives are blocked here, switching and draining
  11437. // is atomical in respect to the new channel
  11438. SwitchDefaultOutChannelSelector();
  11439. // make sure everybody who was submitting is out
  11440. OutChannel->DrainPendingSubmissions();
  11441. // 1 is for the lock that we have
  11442. ChannelPtr->DrainPendingLocks(1);
  11443. RpcStatus = OutChannel->TransferReceiveStateToNewChannel(OutChannel2);
  11444. if (RpcStatus != RPC_S_OK)
  11445. {
  11446. OutChannel2->UnblockDataReceives();
  11447. NewChannelPtr->UnlockChannelPointer();
  11448. ChannelPtr->UnlockChannelPointer();
  11449. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11450. RpcStatus = RPC_P_PACKET_CONSUMED;
  11451. break;
  11452. }
  11453. // if there is recv pending, but it is not an sync recv,
  11454. // make a note of that - we will resubmit it later. If it is
  11455. // sync, we will use the ReissueRecv mechanism to transfer
  11456. // the recv to the new channel
  11457. DataReceivePosted = FALSE;
  11458. if (OutChannel->IsDataReceivePosted())
  11459. {
  11460. if (OutChannel->IsSyncRecvPending())
  11461. {
  11462. // before we destroy, tell any pending recv to re-issue
  11463. // itself upon failure.
  11464. ReissueRecv = TRUE;
  11465. }
  11466. else
  11467. {
  11468. DataReceivePosted = TRUE;
  11469. }
  11470. }
  11471. ChannelPtr->UnlockChannelPointer();
  11472. if (ClientPacketType == http2coptD4_A10)
  11473. {
  11474. // after having transfered the receive settings,
  11475. // we can send D4/A11 to open the pipeline
  11476. RpcStatus = ForwardTrafficToDefaultChannel(FALSE, // IsInChannel
  11477. Buffer,
  11478. BufferLength
  11479. );
  11480. if (RpcStatus != RPC_S_OK)
  11481. {
  11482. NewChannelPtr->UnlockChannelPointer();
  11483. OutChannel2->UnblockDataReceives();
  11484. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11485. RpcStatus = RPC_P_PACKET_CONSUMED;
  11486. break;
  11487. }
  11488. // we no longer own the buffer
  11489. BufferFreed = TRUE;
  11490. }
  11491. // we couldn't unblock receives earlier because new receives
  11492. // must be synchronized w.r.t. D4/A11 - we can't post
  11493. // real receives before D4/A11 because it will switch WinHttp
  11494. // into receiveing mode. We also can't send D4/A11 before we
  11495. // have transferred the settings
  11496. OutChannel2->UnblockDataReceives();
  11497. NewChannelPtr->UnlockChannelPointer();
  11498. RpcStatus = PostReceiveOnDefaultChannel (FALSE, // IsInChannel
  11499. http2ttRTS);
  11500. if (RpcStatus != RPC_S_OK)
  11501. {
  11502. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11503. RpcStatus = RPC_P_PACKET_CONSUMED;
  11504. break;
  11505. }
  11506. // detach, abort and free lifetime reference
  11507. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  11508. TRUE, // CalledFromUpcallContext
  11509. TRUE, // Abort
  11510. RPC_P_CONNECTION_SHUTDOWN
  11511. );
  11512. InChannelState.Mutex.Request();
  11513. // we haven't posted a receive yet - there is no
  11514. // way the state of the channel will change
  11515. if (ClientPacketType == http2coptD4_A10)
  11516. ExpectedState = http2svOpened_A10W;
  11517. else
  11518. ExpectedState = http2svOpened_B3W;
  11519. ASSERT(OutChannelState.State == ExpectedState);
  11520. // move channel state to opened
  11521. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  11522. OutChannelState.State = http2svOpened;
  11523. InChannelState.Mutex.Clear();
  11524. if (DataReceivePosted)
  11525. {
  11526. RpcStatus = PostReceiveOnDefaultChannel (
  11527. FALSE, // IsInChannel
  11528. http2ttData
  11529. );
  11530. if (RpcStatus != RPC_S_OK)
  11531. {
  11532. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11533. }
  11534. }
  11535. RpcStatus = RPC_P_PACKET_CONSUMED;
  11536. break;
  11537. default:
  11538. ASSERT(0);
  11539. RpcStatus = RPC_S_INTERNAL_ERROR;
  11540. }
  11541. }
  11542. if (MutexReleased == FALSE)
  11543. {
  11544. InChannelState.Mutex.Clear();
  11545. }
  11546. }
  11547. else
  11548. {
  11549. RpcStatus = RPC_S_OK;
  11550. // data packet - ownership of the buffer passes to the runtime
  11551. BufferFreed = TRUE;
  11552. }
  11553. }
  11554. }
  11555. CleanupAndExit:
  11556. if (((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_PACKET_CONSUMED))
  11557. || WakeOpenThread)
  11558. {
  11559. if ((InChannelState.State == http2svA3W)
  11560. || (InChannelState.State == http2svC2W)
  11561. || (InChannelState.State == http2svSearchProxy)
  11562. || WakeOpenThread
  11563. )
  11564. {
  11565. if (ClientOpenInEvent && (InOpenStatus != ERROR_IO_PENDING))
  11566. SetClientOpenInEvent();
  11567. else if (ClientOpenOutEvent && (OutOpenStatus != ERROR_IO_PENDING))
  11568. SetClientOpenOutEvent();
  11569. }
  11570. }
  11571. if (BufferFreed == FALSE)
  11572. RpcFreeBuffer(Buffer);
  11573. return RpcStatus;
  11574. }
  11575. RPC_STATUS HTTP2ClientVirtualConnection::SyncRecv (
  11576. IN BYTE **Buffer,
  11577. IN ULONG *BufferLength,
  11578. IN ULONG Timeout
  11579. )
  11580. /*++
  11581. Routine Description:
  11582. Do a sync receive on an HTTP connection.
  11583. Arguments:
  11584. Buffer - if successful, points to a buffer containing the next PDU.
  11585. BufferLength - if successful, contains the length of the message.
  11586. Timeout - the amount of time to wait for the receive. If -1, we wait
  11587. infinitely.
  11588. Return Value:
  11589. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  11590. --*/
  11591. {
  11592. HTTP2ChannelPointer *ChannelPtr;
  11593. HTTP2ClientChannel *Channel;
  11594. RPC_STATUS RpcStatus;
  11595. BOOL AbortNeeded;
  11596. BOOL IoPending;
  11597. while (TRUE)
  11598. {
  11599. Channel = LockDefaultOutChannel(&ChannelPtr);
  11600. if (Channel)
  11601. {
  11602. RpcStatus = Channel->SubmitSyncRecv(http2ttData);
  11603. // keep a reference for the operations below
  11604. Channel->AddReference();
  11605. ChannelPtr->UnlockChannelPointer();
  11606. IoPending = FALSE;
  11607. if (RpcStatus == RPC_S_OK)
  11608. {
  11609. AbortNeeded = FALSE;
  11610. RpcStatus = Channel->WaitForSyncRecv(Buffer,
  11611. BufferLength,
  11612. Timeout,
  11613. ConnectionTimeout,
  11614. this,
  11615. &AbortNeeded,
  11616. &IoPending
  11617. );
  11618. }
  11619. else
  11620. {
  11621. AbortNeeded = TRUE;
  11622. }
  11623. if (AbortNeeded)
  11624. {
  11625. Channel->Abort(RpcStatus);
  11626. }
  11627. if (IoPending)
  11628. {
  11629. Channel->WaitInfiniteForSyncReceive();
  11630. Channel->RemoveEvent();
  11631. }
  11632. if (AbortNeeded)
  11633. {
  11634. if (ReissueRecv)
  11635. {
  11636. ReissueRecv = FALSE;
  11637. // we don't re-issue on time outs
  11638. if (RpcStatus != RPC_S_CALL_CANCELLED)
  11639. {
  11640. Channel->RemoveReference();
  11641. continue;
  11642. }
  11643. }
  11644. else
  11645. {
  11646. // ASSERT(!"This test should not have failing receives\n");
  11647. }
  11648. }
  11649. Channel->RemoveReference();
  11650. if (RpcStatus == RPC_S_OK)
  11651. {
  11652. ASSERT(*Buffer != NULL);
  11653. ASSERT(IsBadWritePtr(*Buffer, 4) == FALSE);
  11654. }
  11655. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  11656. || (RpcStatus == RPC_P_SEND_FAILED)
  11657. || (RpcStatus == RPC_S_SERVER_UNAVAILABLE)
  11658. || (RpcStatus == RPC_P_CONNECTION_CLOSED) )
  11659. {
  11660. RpcStatus = RPC_P_RECEIVE_FAILED;
  11661. }
  11662. break;
  11663. }
  11664. else
  11665. {
  11666. RpcStatus = RPC_P_RECEIVE_FAILED;
  11667. break;
  11668. }
  11669. }
  11670. VALIDATE(RpcStatus)
  11671. {
  11672. RPC_S_OK,
  11673. RPC_S_OUT_OF_MEMORY,
  11674. RPC_S_OUT_OF_RESOURCES,
  11675. RPC_P_RECEIVE_FAILED,
  11676. RPC_S_CALL_CANCELLED,
  11677. RPC_P_SEND_FAILED,
  11678. RPC_P_CONNECTION_SHUTDOWN,
  11679. RPC_P_TIMEOUT
  11680. } END_VALIDATE;
  11681. return RpcStatus;
  11682. }
  11683. void HTTP2ClientVirtualConnection::Abort (
  11684. void
  11685. )
  11686. /*++
  11687. Routine Description:
  11688. Aborts an HTTP connection and disconnects the channels.
  11689. Must only come from the runtime.
  11690. Note: Don't call any virtual methods in this function. It
  11691. may be called in an environment without fully initialized
  11692. vtable.
  11693. Arguments:
  11694. Return Value:
  11695. --*/
  11696. {
  11697. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CLIENT_VC, 0);
  11698. // abort the channels themselves
  11699. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11700. // we got to the destructive phase of the abort
  11701. // guard against double aborts
  11702. if (Aborted.Increment() > 1)
  11703. return;
  11704. HTTP2VirtualConnection::DisconnectChannels(FALSE, 0);
  11705. // call destructor without freeing memory
  11706. HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  11707. }
  11708. void HTTP2ClientVirtualConnection::Close (
  11709. IN BOOL DontFlush
  11710. )
  11711. /*++
  11712. Routine Description:
  11713. Closes a client HTTP connection.
  11714. Note: Don't call virtual functions in this method.
  11715. It may be called in an environment without fully
  11716. initialized vtable.
  11717. Arguments:
  11718. DontFlush - non-zero if all buffers need to be flushed
  11719. before closing the connection. Zero otherwise.
  11720. Return Value:
  11721. --*/
  11722. {
  11723. HTTP2ClientVirtualConnection::Abort();
  11724. }
  11725. RPC_STATUS HTTP2ClientVirtualConnection::TurnOnOffKeepAlives (
  11726. IN BOOL TurnOn,
  11727. IN BOOL bProtectIO,
  11728. IN BOOL IsFromUpcall,
  11729. IN KEEPALIVE_TIMEOUT_UNITS Units,
  11730. IN OUT KEEPALIVE_TIMEOUT KATime,
  11731. IN ULONG KAInterval OPTIONAL
  11732. )
  11733. /*++
  11734. Routine Description:
  11735. Turns on keep alives for HTTP.
  11736. Arguments:
  11737. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  11738. are turned off.
  11739. bProtectIO - non-zero if IO needs to be protected against async close
  11740. of the connection.
  11741. IsFromUpcall - non-zero if called from upcall context. Zero otherwise.
  11742. Units - in what units is KATime
  11743. KATime - how much to wait before turning on keep alives
  11744. KAInterval - the interval between keep alives
  11745. Return Value:
  11746. RPC_S_OK or RPC_S_* / Win32 errors on failure
  11747. Note:
  11748. If we were to use it on the server, we must protect
  11749. the connection against async aborts.
  11750. Called in upcall or runtime context only.
  11751. --*/
  11752. {
  11753. HTTP2ClientInChannel *InChannel;
  11754. int i;
  11755. RPC_STATUS RpcStatus;
  11756. if (TurnOn)
  11757. CurrentKeepAlive = KAInterval;
  11758. else
  11759. CurrentKeepAlive = 0;
  11760. // convert the timeout from runtime scale to transport scale
  11761. if (Units == tuRuntime)
  11762. {
  11763. ASSERT(KATime.RuntimeUnits != RPC_C_BINDING_INFINITE_TIMEOUT);
  11764. KATime.Milliseconds = ConvertRuntimeTimeoutToWSTimeout(KATime.RuntimeUnits);
  11765. Units = tuMilliseconds;
  11766. }
  11767. // make the change on both channels
  11768. for (i = 0; i < 2; i ++)
  11769. {
  11770. InChannel = (HTTP2ClientInChannel *)InChannels[i].LockChannelPointer();
  11771. if (InChannel != NULL)
  11772. {
  11773. RpcStatus = InChannel->SetKeepAliveTimeout (
  11774. TurnOn,
  11775. bProtectIO,
  11776. Units,
  11777. KATime,
  11778. KATime.Milliseconds
  11779. );
  11780. InChannels[i].UnlockChannelPointer();
  11781. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  11782. IsFromUpcall
  11783. );
  11784. if (RpcStatus != RPC_S_OK)
  11785. break;
  11786. }
  11787. }
  11788. return RpcStatus;
  11789. }
  11790. RPC_STATUS HTTP2ClientVirtualConnection::RecycleChannel (
  11791. IN BOOL IsFromUpcall
  11792. )
  11793. /*++
  11794. Routine Description:
  11795. An in channel recycle is initiated. This may be called
  11796. in an upcall or runtime context.
  11797. Arguments:
  11798. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  11799. Return Value:
  11800. RPC_S_OK or other RPC_S_* errors for error
  11801. --*/
  11802. {
  11803. RPC_STATUS RpcStatus;
  11804. HTTP2ClientInChannel *NewInChannel;
  11805. int NonDefaultInChannelSelector;
  11806. HTTP2ChannelPointer *NewInChannelPtr;
  11807. HTTP2SendContext *D2_A1Context;
  11808. BOOL UseWinHttp;
  11809. #if DBG
  11810. DbgPrint("RPCRT4: %d Recycling IN channel\n", GetCurrentProcessId());
  11811. #endif
  11812. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  11813. // we shouldn't get recycle unless we're in an opened state
  11814. ASSERT(InChannelState.State == http2svOpened);
  11815. // create a new in channel
  11816. RpcStatus = ClientOpenInternal (&ConnectionHint,
  11817. TRUE, // HintWasInitialize
  11818. ConnectionTimeout,
  11819. DefaultReplacementChannelCallTimeout,
  11820. TRUE, // ClientOpenInChannel,
  11821. FALSE, // ClientOpenOutChannel
  11822. TRUE, // IsReplacementChannel
  11823. IsFromUpcall
  11824. );
  11825. if (RpcStatus != RPC_S_OK)
  11826. {
  11827. // ClientOpenInternal Aborts on failure. No need to abort
  11828. // here
  11829. return RpcStatus;
  11830. }
  11831. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  11832. NewInChannelPtr = &InChannels[NonDefaultInChannelSelector];
  11833. NewInChannel = (HTTP2ClientInChannel *)NewInChannelPtr->LockChannelPointer();
  11834. if (NewInChannel == NULL)
  11835. {
  11836. Abort();
  11837. return RPC_P_CONNECTION_SHUTDOWN;
  11838. }
  11839. InChannelState.Mutex.Request();
  11840. if (InChannelState.State != http2svOpened)
  11841. {
  11842. InChannelState.Mutex.Clear();
  11843. NewInChannelPtr->UnlockChannelPointer();
  11844. Abort();
  11845. return RPC_P_CONNECTION_SHUTDOWN;
  11846. }
  11847. // move to Opened_A4W in anticipation of the send we will make.
  11848. InChannelState.State = http2svOpened_A4W;
  11849. InChannelState.Mutex.Clear();
  11850. D2_A1Context = AllocateAndInitializeD2_A1(HTTP2ProtocolVersion,
  11851. &EmbeddedConnectionCookie,
  11852. &InChannelCookies[DefaultInChannelSelector],
  11853. &InChannelCookies[NonDefaultInChannelSelector]
  11854. );
  11855. if (D2_A1Context == NULL)
  11856. {
  11857. NewInChannelPtr->UnlockChannelPointer();
  11858. Abort();
  11859. return RPC_S_OUT_OF_MEMORY;
  11860. }
  11861. RpcStatus = NewInChannel->Send(D2_A1Context);
  11862. if (RpcStatus != RPC_S_OK)
  11863. {
  11864. NewInChannelPtr->UnlockChannelPointer();
  11865. FreeRTSPacket(D2_A1Context);
  11866. Abort();
  11867. return RpcStatus;
  11868. }
  11869. if (!UseWinHttp)
  11870. {
  11871. RpcStatus = NewInChannel->Receive(http2ttRaw);
  11872. }
  11873. NewInChannelPtr->UnlockChannelPointer();
  11874. if (RpcStatus != RPC_S_OK)
  11875. {
  11876. Abort();
  11877. }
  11878. return RpcStatus;
  11879. }
  11880. RPC_STATUS HTTP2ClientVirtualConnection::OpenReplacementOutChannel (
  11881. void
  11882. )
  11883. /*++
  11884. Routine Description:
  11885. Opens a replacement out channel. Used during out channel
  11886. recycling.
  11887. Arguments:
  11888. Return Value:
  11889. RPC_S_OK or other RPC_S_* errors for error
  11890. --*/
  11891. {
  11892. RPC_STATUS RpcStatus;
  11893. HTTP2ClientOutChannel *NewOutChannel;
  11894. int NonDefaultOutChannelSelector;
  11895. HTTP2ChannelPointer *NewOutChannelPtr;
  11896. HTTP2SendContext *D4_A3Context;
  11897. KEEPALIVE_TIMEOUT KATime;
  11898. // create a new out channel
  11899. RpcStatus = ClientOpenInternal (&ConnectionHint,
  11900. TRUE, // HintWasInitialize
  11901. ConnectionTimeout,
  11902. DefaultReplacementChannelCallTimeout,
  11903. FALSE, // ClientOpenInChannel,
  11904. TRUE, // ClientOpenOutChannel
  11905. TRUE, // IsReplacementChannel
  11906. TRUE // IsFromUpcall
  11907. );
  11908. if (RpcStatus != RPC_S_OK)
  11909. {
  11910. // ClientOpenInternal has already aborted the connection
  11911. return RpcStatus;
  11912. }
  11913. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  11914. NewOutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  11915. NewOutChannel = (HTTP2ClientOutChannel *)NewOutChannelPtr->LockChannelPointer();
  11916. if (NewOutChannel == NULL)
  11917. {
  11918. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11919. return RPC_P_CONNECTION_SHUTDOWN;
  11920. }
  11921. InChannelState.Mutex.Request();
  11922. if (OutChannelState.State != http2svOpened)
  11923. {
  11924. InChannelState.Mutex.Clear();
  11925. NewOutChannelPtr->UnlockChannelPointer();
  11926. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11927. return RPC_P_CONNECTION_SHUTDOWN;
  11928. }
  11929. // move to Opened_A6W in anticipation of the send we will make.
  11930. OutChannelState.State = http2svOpened_A6W;
  11931. InChannelState.Mutex.Clear();
  11932. D4_A3Context = AllocateAndInitializeD4_A3(HTTP2ProtocolVersion,
  11933. &EmbeddedConnectionCookie,
  11934. &OutChannelCookies[DefaultOutChannelSelector],
  11935. &OutChannelCookies[NonDefaultOutChannelSelector],
  11936. HTTP2DefaultClientReceiveWindow
  11937. );
  11938. if (D4_A3Context == NULL)
  11939. {
  11940. NewOutChannelPtr->UnlockChannelPointer();
  11941. AbortChannels(RPC_S_OUT_OF_MEMORY);
  11942. return RPC_S_OUT_OF_MEMORY;
  11943. }
  11944. RpcStatus = NewOutChannel->Send(D4_A3Context);
  11945. if (RpcStatus != RPC_S_OK)
  11946. {
  11947. NewOutChannelPtr->UnlockChannelPointer();
  11948. FreeRTSPacket(D4_A3Context);
  11949. AbortChannels(RpcStatus);
  11950. return RpcStatus;
  11951. }
  11952. if (CurrentKeepAlive)
  11953. {
  11954. KATime.Milliseconds = 0;
  11955. RpcStatus = NewOutChannel->SetKeepAliveTimeout (
  11956. TRUE, // TurnOn
  11957. FALSE, // bProtectIO
  11958. tuMilliseconds,
  11959. KATime,
  11960. CurrentKeepAlive
  11961. );
  11962. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  11963. }
  11964. NewOutChannelPtr->UnlockChannelPointer();
  11965. if (RpcStatus != RPC_S_OK)
  11966. {
  11967. AbortChannels(RpcStatus);
  11968. }
  11969. return RpcStatus;
  11970. }
  11971. void HTTP2ClientVirtualConnection::AbortChannels (
  11972. IN RPC_STATUS RpcStatus
  11973. )
  11974. /*++
  11975. Routine Description:
  11976. Aborts an HTTP connection but does not disconnect
  11977. the channels. Can be called from above, upcall, or
  11978. neutral context, but not from submit context!
  11979. Arguments:
  11980. RpcStatus - the error to abort the channels with
  11981. Return Value:
  11982. --*/
  11983. {
  11984. if (IgnoreAborts == FALSE)
  11985. HTTP2VirtualConnection::AbortChannels (RpcStatus);
  11986. }
  11987. HTTP2Channel *HTTP2ClientVirtualConnection::LockDefaultSendChannel (
  11988. OUT HTTP2ChannelPointer **ChannelPtr
  11989. )
  11990. /*++
  11991. Routine Description:
  11992. Locks the send channel. For client connections this is the in channel.
  11993. Arguments:
  11994. ChannelPtr - on success, the channel pointer to use.
  11995. Return Value:
  11996. The locked channel or NULL (same semantics as LockDefaultOutChannel)
  11997. --*/
  11998. {
  11999. return LockDefaultInChannel(ChannelPtr);
  12000. }
  12001. HTTP2Channel *HTTP2ClientVirtualConnection::LockDefaultReceiveChannel (
  12002. OUT HTTP2ChannelPointer **ChannelPtr
  12003. )
  12004. /*++
  12005. Routine Description:
  12006. Locks the receive channel. For client connections this is the out channel.
  12007. Arguments:
  12008. ChannelPtr - on success, the channel pointer to use.
  12009. Return Value:
  12010. The locked channel or NULL (same semantics as LockDefaultInChannel)
  12011. --*/
  12012. {
  12013. return LockDefaultOutChannel(ChannelPtr);
  12014. }
  12015. const int MaxOutChannelHeader = 300;
  12016. RPC_STATUS
  12017. RPC_ENTRY
  12018. HTTP2ClientReadChannelHeader (
  12019. IN WS_HTTP2_CONNECTION *Connection,
  12020. IN ULONG BytesRead,
  12021. OUT ULONG *NewBytesRead
  12022. )
  12023. /*++
  12024. Routine Description:
  12025. Read a channel HTTP header (usually some string). In success
  12026. case, there is real data in Connection->pReadBuffer. The
  12027. number of bytes there is in NewBytesRead
  12028. Arguments:
  12029. Connection - the connection on which the header arrived.
  12030. BytesRead - the bytes received from the net
  12031. NewBytesRead - the bytes read from the channel (success only)
  12032. Return Value:
  12033. RPC_S_OK or other RPC_S_* errors for error
  12034. --*/
  12035. {
  12036. DWORD message_size;
  12037. RPC_STATUS RpcStatus;
  12038. char *CurrentPosition;
  12039. char *LastPosition; // first position after end
  12040. char *LastPosition2; // first position after end + 4
  12041. // useful for end-of-loop comparison
  12042. char *StartPosition;
  12043. char *HeaderEnd; // first character after header end
  12044. ULONG HTTPResponse;
  12045. BYTE *NewBuffer;
  12046. BytesRead += Connection->iLastRead;
  12047. // we have read something. Let's process it now.
  12048. // search for double CR-LF (\r\n\r\n)
  12049. StartPosition = (char *)(Connection->pReadBuffer);
  12050. LastPosition = StartPosition + BytesRead;
  12051. LastPosition2 = LastPosition + 4;
  12052. HeaderEnd = NULL;
  12053. CurrentPosition = (char *)(Connection->pReadBuffer);
  12054. while (CurrentPosition < LastPosition2)
  12055. {
  12056. if ((*CurrentPosition == '\r')
  12057. && (*(CurrentPosition + 1) == '\n')
  12058. && (*(CurrentPosition + 2) == '\r')
  12059. && (*(CurrentPosition + 3) == '\n')
  12060. )
  12061. {
  12062. // we have a full header
  12063. HeaderEnd = CurrentPosition + 4;
  12064. break;
  12065. }
  12066. CurrentPosition ++;
  12067. }
  12068. if (CurrentPosition - StartPosition >= MaxOutChannelHeader)
  12069. {
  12070. // we should have seen the header by now. Abort. Returning
  12071. // failure is enough - we know the caller will abort
  12072. return RPC_S_PROTOCOL_ERROR;
  12073. }
  12074. if (HeaderEnd == NULL)
  12075. {
  12076. // we didn't find the end of the header. Submit another receive
  12077. // for the rest
  12078. RpcStatus = TransConnectionReallocPacket(Connection,
  12079. &Connection->pReadBuffer,
  12080. BytesRead,
  12081. MaxOutChannelHeader);
  12082. if (RpcStatus != RPC_S_OK)
  12083. {
  12084. ASSERT(RpcStatus == RPC_S_OUT_OF_MEMORY);
  12085. return(RpcStatus);
  12086. }
  12087. Connection->iLastRead = BytesRead;
  12088. Connection->maxReadBuffer = MaxOutChannelHeader;
  12089. return RPC_P_PARTIAL_RECEIVE;
  12090. }
  12091. // we have found the header end. Grab the status code
  12092. HTTPResponse = HttpParseResponse(StartPosition);
  12093. if ((HTTPResponse >= RPC_S_INVALID_STRING_BINDING) && (HTTPResponse <= RPC_X_BAD_STUB_DATA))
  12094. {
  12095. // if it is an RPC error code, just return it.
  12096. return HTTPResponse;
  12097. }
  12098. if (HTTPResponse != 200)
  12099. return RPC_S_PROTOCOL_ERROR;
  12100. // check whether we have something else besides the HTTP header
  12101. if (HeaderEnd < LastPosition)
  12102. {
  12103. NewBuffer = TransConnectionAllocatePacket(Connection,
  12104. LastPosition - HeaderEnd);
  12105. if (0 == NewBuffer)
  12106. return RPC_S_OUT_OF_MEMORY;
  12107. RpcpMemoryCopy(NewBuffer, HeaderEnd, LastPosition - HeaderEnd);
  12108. *NewBytesRead = LastPosition - HeaderEnd;
  12109. RpcFreeBuffer(Connection->pReadBuffer);
  12110. Connection->pReadBuffer = NewBuffer;
  12111. Connection->maxReadBuffer = LastPosition - HeaderEnd;
  12112. Connection->iLastRead = 0;
  12113. Connection->HeaderRead = TRUE;
  12114. return RPC_S_OK;
  12115. }
  12116. // reset the pointer. By doing so we forget all we have
  12117. // read so far (which is only the HTTP header anyway)
  12118. Connection->iLastRead = 0;
  12119. Connection->HeaderRead = TRUE;
  12120. return RPC_P_PARTIAL_RECEIVE;
  12121. }
  12122. // this is a bit mask. For any particular scheme, AND it with the constant
  12123. // Non-zero means it is multillegged. Schemes are:
  12124. // Scheme Value Multilegged
  12125. // RPC_C_HTTP_AUTHN_SCHEME_BASIC 0x00000001 0
  12126. // RPC_C_HTTP_AUTHN_SCHEME_NTLM 0x00000002 1
  12127. // RPC_C_HTTP_AUTHN_SCHEME_PASSPORT 0x00000004 1
  12128. // RPC_C_HTTP_AUTHN_SCHEME_DIGEST 0x00000008 1
  12129. // RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE 0x00000010 1
  12130. const ULONG MultiLeggedSchemeMap =
  12131. RPC_C_HTTP_AUTHN_SCHEME_NTLM
  12132. | RPC_C_HTTP_AUTHN_SCHEME_PASSPORT
  12133. | RPC_C_HTTP_AUTHN_SCHEME_DIGEST
  12134. | RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE;
  12135. /*
  12136. All client opened types are valid initial states. The transitions are:
  12137. cotSearchProxy ------+----> cotUknownAuth
  12138. |
  12139. +----------------+---------------+
  12140. | | |
  12141. cotMLAuth cotSLAuth cotNoAuth
  12142. |
  12143. cotMLAuth2
  12144. */
  12145. typedef enum tagClientOpenTypes
  12146. {
  12147. cotSearchProxy,
  12148. cotNoAuth,
  12149. cotMLAuth,
  12150. cotMLAuth2,
  12151. cotSLAuth,
  12152. cotUnknownAuth,
  12153. cotInvalid
  12154. } ClientOpenTypes;
  12155. const char *InHeaderVerb = "RPC_IN_DATA";
  12156. const int InHeaderVerbLength = 11; // length of RPC_IN_DATA
  12157. const char *OutHeaderVerb = "RPC_OUT_DATA";
  12158. const int OutHeaderVerbLength = 12; // length of RPC_OUT_DATA
  12159. const BYTE EchoData[4] = {0xF8, 0xE8, 0x18, 0x08};
  12160. const ULONG EchoDataLength = sizeof(EchoData);
  12161. RPC_STATUS HTTP2ClientVirtualConnection::ClientOpenInternal (
  12162. IN HTTPResolverHint *Hint,
  12163. IN BOOL HintWasInitialized,
  12164. IN UINT ConnTimeout,
  12165. IN ULONG CallTimeout,
  12166. IN BOOL ClientOpenInChannel,
  12167. IN BOOL ClientOpenOutChannel,
  12168. IN BOOL IsReplacementChannel,
  12169. IN BOOL IsFromUpcall
  12170. )
  12171. /*++
  12172. Routine Description:
  12173. Opens a client side virtual connection.
  12174. Arguments:
  12175. Hint - the resolver hint
  12176. HintWasInitialized - the hint was initialized on input.
  12177. ConnTimeout - connection timeout
  12178. CallTimeout - operation timeout
  12179. ClientOpenInChannel - non-zero if the in channel is to be opened.
  12180. ClientOpenOutChannel - non-zero if the out channel is to be
  12181. opened.
  12182. IsReplacementChannel - non-zero if this is channel recycling
  12183. IsFromUpcall - non-zero if this is called from an upcall. Zero otherwise.
  12184. Return Value:
  12185. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  12186. --*/
  12187. {
  12188. RPC_STATUS RpcStatus;
  12189. HTTP2ClientInChannel *NewInChannel;
  12190. HTTP2ClientOutChannel *NewOutChannel;
  12191. BOOL InChannelLocked;
  12192. BOOL OutChannelLocked;
  12193. HTTP2SendContext *OutChannelSendContext = NULL;
  12194. HTTP2SendContext *InChannelSendContext = NULL;
  12195. ULONG WaitResult;
  12196. HANDLE LocalClientOpenEvent;
  12197. BOOL UseWinHttp;
  12198. KEEPALIVE_TIMEOUT KATimeout;
  12199. BOOL RebuildInChannel;
  12200. BOOL RebuildOutChannel;
  12201. BOOL NukeInChannel;
  12202. BOOL NukeOutChannel;
  12203. BOOL ResetInChannel;
  12204. BOOL ResetOutChannel;
  12205. BOOL SendInChannel;
  12206. BOOL SendOutChannel;
  12207. BOOL OpenInChannel;
  12208. BOOL OpenOutChannel;
  12209. BOOL ReceiveInChannel;
  12210. BOOL ReceiveOutChannel;
  12211. RPCProxyAccessType StoredAccessType;
  12212. const char *VerbToUse;
  12213. int VerbLengthToUse;
  12214. const BYTE *AdditionalDataToUse;
  12215. ULONG AdditionalDataLengthToUse;
  12216. HTTP2StateValues NewConnectionState = http2svInvalid;
  12217. BOOL SetNewConnectionState;
  12218. RPC_STATUS LocalInOpenStatus;
  12219. RPC_STATUS LocalOutOpenStatus;
  12220. ULONG InChosenAuthScheme;
  12221. ULONG OutChosenAuthScheme;
  12222. BOOL IsKeepAlive;
  12223. BOOL IsDone;
  12224. int NonDefaultInChannelSelector;
  12225. int NonDefaultOutChannelSelector;
  12226. HTTP2ChannelPointer *InChannelPtr;
  12227. HTTP2ChannelPointer *OutChannelPtr;
  12228. ClientOpenTypes InOpenType;
  12229. ClientOpenTypes OutOpenType;
  12230. ClientOpenTypes OldOpenType;
  12231. ClientOpenTypes OldInOpenType;
  12232. ClientOpenTypes OldOutOpenType;
  12233. int CurrentCase;
  12234. #if DBG
  12235. int NumberOfRetries = 0;
  12236. #endif
  12237. if (IsReplacementChannel == FALSE)
  12238. {
  12239. if (ConnTimeout != RPC_C_BINDING_INFINITE_TIMEOUT)
  12240. {
  12241. ASSERT( ((long)ConnTimeout >= RPC_C_BINDING_MIN_TIMEOUT)
  12242. && (ConnTimeout <= RPC_C_BINDING_MAX_TIMEOUT));
  12243. // convert the timeout from runtime scale to transport scale
  12244. ConnectionTimeout = ConvertRuntimeTimeoutToWSTimeout(ConnTimeout);
  12245. }
  12246. else
  12247. {
  12248. ConnectionTimeout = INFINITE;
  12249. }
  12250. }
  12251. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  12252. if (UseWinHttp)
  12253. {
  12254. RpcStatus = InitWinHttpIfNecessary();
  12255. if (RpcStatus != RPC_S_OK)
  12256. return RpcStatus;
  12257. }
  12258. InOpenType = OutOpenType = cotInvalid;
  12259. InChosenAuthScheme = 0;
  12260. OutChosenAuthScheme = 0;
  12261. IsDone = FALSE;
  12262. if (HttpCredentials)
  12263. {
  12264. // WinHttp5.x does not support pre-auth for digest. This means that even if
  12265. // you know that digest is your scheme, you have to pretend that you don't
  12266. // and wait for the challenge before you choose it. Otherwise WinHttp5.x will
  12267. // complain and fail.
  12268. if ((HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME)
  12269. && (*(HttpCredentials->AuthnSchemes) != RPC_C_HTTP_AUTHN_SCHEME_DIGEST))
  12270. {
  12271. OutChosenAuthScheme = InChosenAuthScheme = *(HttpCredentials->AuthnSchemes);
  12272. if (ClientOpenInChannel)
  12273. {
  12274. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  12275. InOpenType = cotMLAuth;
  12276. else
  12277. InOpenType = cotSLAuth;
  12278. }
  12279. if (ClientOpenOutChannel)
  12280. {
  12281. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  12282. OutOpenType = cotMLAuth;
  12283. else
  12284. OutOpenType = cotSLAuth;
  12285. }
  12286. }
  12287. }
  12288. else if (IsReplacementChannel == FALSE)
  12289. {
  12290. ASSERT(OutOpenType == cotInvalid);
  12291. InOpenType = OutOpenType = cotNoAuth;
  12292. }
  12293. else if (ClientOpenInChannel)
  12294. {
  12295. InOpenType = cotNoAuth;
  12296. IsDone = TRUE;
  12297. }
  12298. else
  12299. {
  12300. OutOpenType = cotNoAuth;
  12301. IsDone = TRUE;
  12302. }
  12303. LocalClientOpenEvent = CreateEvent(NULL, // lpEventAttributes
  12304. FALSE, // bManualReset
  12305. FALSE, // bInitialState
  12306. NULL // lpName
  12307. );
  12308. if (LocalClientOpenEvent == NULL)
  12309. return RPC_S_OUT_OF_MEMORY;
  12310. if (IsReplacementChannel == FALSE)
  12311. {
  12312. RpcStatus = EmbeddedConnectionCookie.Create();
  12313. if (RpcStatus != RPC_S_OK)
  12314. goto AbortAndExit;
  12315. }
  12316. else
  12317. {
  12318. if (ClientOpenInChannel)
  12319. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  12320. else
  12321. {
  12322. ASSERT(ClientOpenOutChannel);
  12323. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  12324. }
  12325. }
  12326. if (ClientOpenInChannel)
  12327. {
  12328. if (IsReplacementChannel)
  12329. RpcStatus = InChannelCookies[NonDefaultInChannelSelector].Create();
  12330. else
  12331. RpcStatus = InChannelCookies[0].Create();
  12332. if (RpcStatus != RPC_S_OK)
  12333. goto AbortAndExit;
  12334. }
  12335. if (ClientOpenOutChannel)
  12336. {
  12337. if (IsReplacementChannel)
  12338. RpcStatus = OutChannelCookies[NonDefaultOutChannelSelector].Create();
  12339. else
  12340. RpcStatus = OutChannelCookies[0].Create();
  12341. if (RpcStatus != RPC_S_OK)
  12342. goto AbortAndExit;
  12343. }
  12344. if (ClientOpenInChannel)
  12345. {
  12346. RebuildInChannel = TRUE;
  12347. NukeInChannel = FALSE;
  12348. ResetInChannel = FALSE;
  12349. OpenInChannel = TRUE;
  12350. InOpenStatus = ERROR_IO_PENDING;
  12351. }
  12352. else
  12353. {
  12354. RebuildInChannel = FALSE;
  12355. NukeInChannel = FALSE;
  12356. ResetInChannel = FALSE;
  12357. OpenInChannel = FALSE;
  12358. ReceiveInChannel = FALSE;
  12359. }
  12360. InChannelLocked = FALSE;
  12361. if (ClientOpenOutChannel)
  12362. {
  12363. RebuildOutChannel = TRUE;
  12364. NukeOutChannel = FALSE;
  12365. ResetOutChannel = FALSE;
  12366. OpenOutChannel = TRUE;
  12367. // receive is done below
  12368. OutOpenStatus = ERROR_IO_PENDING;
  12369. }
  12370. else
  12371. {
  12372. RebuildOutChannel = FALSE;
  12373. NukeOutChannel = FALSE;
  12374. ResetOutChannel = FALSE;
  12375. OpenOutChannel = FALSE;
  12376. ReceiveOutChannel = FALSE;
  12377. }
  12378. OutChannelLocked = FALSE;
  12379. SetNewConnectionState = FALSE;
  12380. ClientOpenInEvent = ClientOpenOutEvent = LocalClientOpenEvent;
  12381. ASSERT(InChosenAuthScheme == OutChosenAuthScheme);
  12382. // do we know whether to use a proxy?
  12383. StoredAccessType = Hint->AccessType;
  12384. if (StoredAccessType == rpcpatUnknown)
  12385. {
  12386. // this should never happen for replacement channels
  12387. ASSERT(IsReplacementChannel == FALSE);
  12388. // we don't.
  12389. InOpenType = OutOpenType = cotSearchProxy;
  12390. // move to http2svSearchProxy
  12391. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svSearchProxy, 1, 0);
  12392. InChannelState.State = http2svSearchProxy;
  12393. SendInChannel = FALSE;
  12394. SendOutChannel = FALSE;
  12395. ReceiveInChannel = TRUE;
  12396. ReceiveOutChannel = TRUE;
  12397. }
  12398. else
  12399. {
  12400. // we know. Do we know what authentication to use?
  12401. if (InChosenAuthScheme)
  12402. {
  12403. ASSERT(InChosenAuthScheme == OutChosenAuthScheme);
  12404. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  12405. {
  12406. if (ClientOpenInChannel)
  12407. InOpenType = cotMLAuth;
  12408. else
  12409. InOpenType = cotInvalid;
  12410. if (ClientOpenOutChannel)
  12411. {
  12412. OutOpenType = cotMLAuth;
  12413. ReceiveOutChannel = TRUE;
  12414. }
  12415. else
  12416. {
  12417. OutOpenType = cotInvalid;
  12418. ReceiveOutChannel = FALSE;
  12419. }
  12420. }
  12421. else
  12422. {
  12423. if (ClientOpenInChannel)
  12424. {
  12425. InOpenType = cotSLAuth;
  12426. if (IsReplacementChannel)
  12427. IsDone = TRUE;
  12428. }
  12429. else
  12430. InOpenType = cotInvalid;
  12431. if (ClientOpenOutChannel)
  12432. {
  12433. OutOpenType = cotSLAuth;
  12434. if (IsReplacementChannel)
  12435. {
  12436. ReceiveOutChannel = FALSE;
  12437. IsDone = TRUE;
  12438. }
  12439. else
  12440. ReceiveOutChannel = TRUE;
  12441. }
  12442. else
  12443. {
  12444. OutOpenType = cotInvalid;
  12445. ReceiveOutChannel = FALSE;
  12446. }
  12447. }
  12448. }
  12449. else
  12450. {
  12451. if (ClientOpenInChannel)
  12452. {
  12453. if (InOpenType != cotNoAuth)
  12454. InOpenType = cotUnknownAuth;
  12455. }
  12456. else
  12457. InOpenType = cotInvalid;
  12458. if (ClientOpenOutChannel)
  12459. {
  12460. if (OutOpenType != cotNoAuth)
  12461. {
  12462. OutOpenType = cotUnknownAuth;
  12463. ReceiveOutChannel = TRUE;
  12464. }
  12465. else if (IsReplacementChannel)
  12466. ReceiveOutChannel = FALSE;
  12467. else
  12468. ReceiveOutChannel = TRUE;
  12469. }
  12470. else
  12471. {
  12472. OutOpenType = cotInvalid;
  12473. ReceiveOutChannel = FALSE;
  12474. }
  12475. }
  12476. if (IsReplacementChannel == FALSE)
  12477. {
  12478. // move to http2svA3W
  12479. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svA3W, 1, 0);
  12480. InChannelState.State = http2svA3W;
  12481. }
  12482. if (
  12483. (
  12484. (InOpenType == cotSLAuth)
  12485. ||
  12486. (InOpenType == cotNoAuth)
  12487. )
  12488. &&
  12489. (IsReplacementChannel == FALSE)
  12490. )
  12491. {
  12492. SendInChannel = TRUE;
  12493. }
  12494. else
  12495. SendInChannel = FALSE;
  12496. if (
  12497. (
  12498. (OutOpenType == cotSLAuth)
  12499. ||
  12500. (OutOpenType == cotNoAuth)
  12501. )
  12502. &&
  12503. (IsReplacementChannel == FALSE)
  12504. )
  12505. {
  12506. SendOutChannel = TRUE;
  12507. }
  12508. else
  12509. SendOutChannel = FALSE;
  12510. // 3 cases for the receive on the in channel
  12511. // 1. If we don't use WinHttp and this is the first open or is in channel replacement,
  12512. // we post a receive on this channel
  12513. // 2. If this is a single legged operation, or this is a replacement channel we don't
  12514. // post a receive.
  12515. // 3. All other cases (we use WinHttp and this is MLAuth/UnknownAuth) we post a receive
  12516. if (ClientOpenInChannel)
  12517. {
  12518. if (!UseWinHttp)
  12519. ReceiveInChannel = TRUE;
  12520. else if ((InOpenType == cotNoAuth) || (InOpenType == cotSLAuth))
  12521. ReceiveInChannel = FALSE;
  12522. else
  12523. ReceiveInChannel = TRUE;
  12524. }
  12525. else
  12526. ReceiveInChannel = FALSE;
  12527. }
  12528. IgnoreAborts = TRUE;
  12529. while (TRUE)
  12530. {
  12531. #if DBG_ERROR
  12532. DbgPrint("Starting loop iteration ....\n");
  12533. NumberOfRetries ++;
  12534. ASSERT (NumberOfRetries < 10);
  12535. #endif
  12536. if (ClientOpenInChannel == FALSE)
  12537. {
  12538. // if we were told not to touch the in channel, make
  12539. // sure we don't
  12540. ASSERT(RebuildInChannel == FALSE
  12541. && NukeInChannel == FALSE
  12542. && ResetInChannel == FALSE
  12543. && SendInChannel == FALSE
  12544. && OpenInChannel == FALSE
  12545. && ReceiveInChannel == FALSE);
  12546. }
  12547. if (ClientOpenOutChannel == FALSE)
  12548. {
  12549. // if we were told not to touch the out channel, make
  12550. // sure we don't
  12551. ASSERT(RebuildOutChannel == FALSE
  12552. && NukeOutChannel == FALSE
  12553. && ResetOutChannel == FALSE
  12554. && SendOutChannel == FALSE
  12555. && OpenOutChannel == FALSE
  12556. && ReceiveOutChannel == FALSE);
  12557. }
  12558. if (NukeInChannel)
  12559. {
  12560. if (IsReplacementChannel)
  12561. InChannelPtr = &InChannels[NonDefaultInChannelSelector];
  12562. else
  12563. InChannelPtr = &InChannels[0];
  12564. InChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  12565. IsReplacementChannel, // CalledFromUpcallContext
  12566. TRUE, // Abort
  12567. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  12568. );
  12569. InOpenStatus = ERROR_IO_PENDING;
  12570. }
  12571. if (NukeOutChannel)
  12572. {
  12573. if (IsReplacementChannel)
  12574. OutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  12575. else
  12576. OutChannelPtr = &OutChannels[0];
  12577. OutChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  12578. IsReplacementChannel, // CalledFromUpcallContext
  12579. TRUE, // Abort
  12580. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  12581. );
  12582. OutOpenStatus = ERROR_IO_PENDING;
  12583. }
  12584. // after both channels are nuked, see whether we need to change the
  12585. // connection state. We have to do this after nuking the channels
  12586. // to avoid a race in ReceiveComplete where late receives may
  12587. // see a different state
  12588. if (SetNewConnectionState)
  12589. {
  12590. ASSERT(NewConnectionState != http2svInvalid);
  12591. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, NewConnectionState, 1, 0);
  12592. InChannelState.State = NewConnectionState;
  12593. SetNewConnectionState = FALSE;
  12594. }
  12595. if (RebuildInChannel)
  12596. {
  12597. if (StoredAccessType == rpcpatUnknown)
  12598. {
  12599. ASSERT((InOpenType == cotSearchProxy)
  12600. || (InOpenType == cotMLAuth)
  12601. || (InOpenType == cotSLAuth)
  12602. );
  12603. // if we don't know the type yet, try
  12604. // direct for the in, proxy for the out.
  12605. // One of them will work.
  12606. Hint->AccessType = rpcpatDirect;
  12607. }
  12608. // initialize in channel
  12609. RpcStatus = AllocateAndInitializeInChannel(Hint,
  12610. HintWasInitialized,
  12611. CallTimeout,
  12612. UseWinHttp,
  12613. &NewInChannel
  12614. );
  12615. // restore the access type
  12616. if (StoredAccessType == rpcpatUnknown)
  12617. {
  12618. Hint->AccessType = StoredAccessType;
  12619. }
  12620. if (RpcStatus != RPC_S_OK)
  12621. {
  12622. goto AbortAndExit;
  12623. }
  12624. if (IsReplacementChannel)
  12625. SetNonDefaultInChannel(NewInChannel);
  12626. else
  12627. SetFirstInChannel(NewInChannel);
  12628. }
  12629. if (RebuildOutChannel)
  12630. {
  12631. if (StoredAccessType == rpcpatUnknown)
  12632. {
  12633. ASSERT((OutOpenType == cotSearchProxy)
  12634. || (OutOpenType == cotMLAuth)
  12635. || (OutOpenType == cotSLAuth)
  12636. );
  12637. // if we don't know the type yet, try
  12638. // direct for the in, proxy for the out.
  12639. // One of them will work.
  12640. Hint->AccessType = rpcpatHTTPProxy;
  12641. }
  12642. // initialize out channel
  12643. RpcStatus = AllocateAndInitializeOutChannel(Hint,
  12644. TRUE, // HintWasInitialized
  12645. CallTimeout,
  12646. UseWinHttp,
  12647. &NewOutChannel
  12648. );
  12649. // restore the access type
  12650. if (StoredAccessType == rpcpatUnknown)
  12651. {
  12652. Hint->AccessType = StoredAccessType;
  12653. }
  12654. if (RpcStatus != RPC_S_OK)
  12655. {
  12656. goto AbortAndExit;
  12657. }
  12658. if (IsReplacementChannel)
  12659. SetNonDefaultOutChannel(NewOutChannel);
  12660. else
  12661. SetFirstOutChannel(NewOutChannel);
  12662. }
  12663. // at least one channel must wait for something to happen
  12664. if (IsReplacementChannel == FALSE)
  12665. {
  12666. ASSERT((InOpenStatus == ERROR_IO_PENDING)
  12667. || (OutOpenStatus == ERROR_IO_PENDING));
  12668. }
  12669. else if (ClientOpenInChannel)
  12670. {
  12671. ASSERT(InOpenStatus == ERROR_IO_PENDING);
  12672. }
  12673. else
  12674. {
  12675. ASSERT(ClientOpenOutChannel);
  12676. ASSERT(OutOpenStatus == ERROR_IO_PENDING);
  12677. }
  12678. if (ResetInChannel || OpenInChannel || SendInChannel)
  12679. {
  12680. // Lock channel
  12681. // after calling ClientOpen, we may be aborted asynchronously at any moment.
  12682. // we will have pending async operations soon. Do the channel access by the
  12683. // book.
  12684. if (IsReplacementChannel)
  12685. InChannelPtr = &InChannels[NonDefaultInChannelSelector];
  12686. else
  12687. InChannelPtr = &InChannels[0];
  12688. NewInChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  12689. if (NewInChannel == NULL)
  12690. {
  12691. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  12692. goto AbortAndExit;
  12693. }
  12694. InChannelLocked = TRUE;
  12695. }
  12696. // Nuke and rebuild are mutually exclusive with Reset
  12697. if (ResetInChannel)
  12698. {
  12699. ASSERT(NukeInChannel == FALSE);
  12700. ASSERT(RebuildInChannel == FALSE);
  12701. NewInChannel->Reset();
  12702. }
  12703. if (OpenInChannel)
  12704. {
  12705. // do we do in_data or echo's?
  12706. if ((InOpenType == cotSearchProxy)
  12707. || (InOpenType == cotMLAuth)
  12708. || (InOpenType == cotUnknownAuth)
  12709. )
  12710. {
  12711. AdditionalDataToUse = EchoData;
  12712. AdditionalDataLengthToUse = EchoDataLength;
  12713. if (StoredAccessType == rpcpatUnknown)
  12714. {
  12715. // if we don't know the type yet, try
  12716. // direct for the in, proxy for the out.
  12717. // One of them will work.
  12718. Hint->AccessType = rpcpatDirect;
  12719. }
  12720. }
  12721. else
  12722. {
  12723. ASSERT((InOpenType == cotSLAuth)
  12724. || (InOpenType == cotNoAuth)
  12725. || (InOpenType == cotMLAuth2)
  12726. );
  12727. ASSERT(StoredAccessType != rpcpatUnknown);
  12728. if (IsReplacementChannel == FALSE)
  12729. {
  12730. ASSERT(SendInChannel);
  12731. }
  12732. else
  12733. {
  12734. ASSERT(SendInChannel == FALSE);
  12735. }
  12736. AdditionalDataToUse = NULL;
  12737. AdditionalDataLengthToUse = 0;
  12738. }
  12739. if (IsReplacementChannel == FALSE)
  12740. {
  12741. RpcStatus = NewInChannel->Unplug();
  12742. // since no sends have been done yet, unplugging cannot fail here
  12743. ASSERT(RpcStatus == RPC_S_OK);
  12744. }
  12745. RpcStatus = NewInChannel->ClientOpen(Hint,
  12746. InHeaderVerb,
  12747. InHeaderVerbLength,
  12748. UseWinHttp,
  12749. HttpCredentials,
  12750. InChosenAuthScheme,
  12751. CallTimeout,
  12752. AdditionalDataToUse,
  12753. AdditionalDataLengthToUse
  12754. );
  12755. // restore the access type
  12756. if (StoredAccessType == rpcpatUnknown)
  12757. {
  12758. Hint->AccessType = StoredAccessType;
  12759. }
  12760. if (RpcStatus != RPC_S_OK)
  12761. goto AbortAndExit;
  12762. }
  12763. if (ResetOutChannel || OpenOutChannel || SendOutChannel)
  12764. {
  12765. if (IsReplacementChannel)
  12766. OutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  12767. else
  12768. OutChannelPtr = &OutChannels[0];
  12769. NewOutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  12770. if (NewOutChannel == NULL)
  12771. {
  12772. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  12773. goto AbortAndExit;
  12774. }
  12775. OutChannelLocked = TRUE;
  12776. }
  12777. // Nuke and rebuild are mutually exclusive with Reset
  12778. if (ResetOutChannel)
  12779. {
  12780. ASSERT(NukeOutChannel == FALSE);
  12781. ASSERT(RebuildOutChannel == FALSE);
  12782. NewOutChannel->Reset();
  12783. }
  12784. if (OpenOutChannel)
  12785. {
  12786. // do we do out_data or echo's?
  12787. if ((OutOpenType == cotSearchProxy)
  12788. || (OutOpenType == cotMLAuth)
  12789. || (OutOpenType == cotUnknownAuth)
  12790. )
  12791. {
  12792. AdditionalDataToUse = EchoData;
  12793. AdditionalDataLengthToUse = 0;
  12794. AdditionalDataLengthToUse = EchoDataLength;
  12795. if (StoredAccessType == rpcpatUnknown)
  12796. {
  12797. // if we don't know the type yet, try
  12798. // direct for the in, proxy for the out.
  12799. // One of them will work.
  12800. Hint->AccessType = rpcpatHTTPProxy;
  12801. }
  12802. }
  12803. else
  12804. {
  12805. ASSERT((OutOpenType == cotNoAuth)
  12806. || (OutOpenType == cotSLAuth)
  12807. || (OutOpenType == cotMLAuth2)
  12808. );
  12809. ASSERT(StoredAccessType != rpcpatUnknown);
  12810. if (IsReplacementChannel == FALSE)
  12811. {
  12812. ASSERT(SendOutChannel);
  12813. }
  12814. else
  12815. {
  12816. ASSERT(SendOutChannel == FALSE);
  12817. }
  12818. AdditionalDataToUse = NULL;
  12819. AdditionalDataLengthToUse = 0;
  12820. }
  12821. RpcStatus = NewOutChannel->ClientOpen(Hint,
  12822. OutHeaderVerb,
  12823. OutHeaderVerbLength,
  12824. IsReplacementChannel, // ReplacementChannel
  12825. UseWinHttp,
  12826. HttpCredentials,
  12827. OutChosenAuthScheme,
  12828. CallTimeout,
  12829. AdditionalDataToUse,
  12830. AdditionalDataLengthToUse
  12831. );
  12832. // restore the access type
  12833. if (StoredAccessType == rpcpatUnknown)
  12834. {
  12835. Hint->AccessType = StoredAccessType;
  12836. }
  12837. if (RpcStatus != RPC_S_OK)
  12838. goto AbortAndExit;
  12839. }
  12840. if (SendInChannel)
  12841. {
  12842. // should not happen during replacement
  12843. ASSERT(IsReplacementChannel == FALSE);
  12844. InChannelSendContext = AllocateAndInitializeD1_B1(HTTP2ProtocolVersion,
  12845. &EmbeddedConnectionCookie,
  12846. &InChannelCookies[0],
  12847. DefaultChannelLifetime,
  12848. DefaultClientKeepAliveInterval,
  12849. &Hint->AssociationGroupId
  12850. );
  12851. if (InChannelSendContext == NULL)
  12852. {
  12853. RpcStatus = RPC_S_OUT_OF_MEMORY;
  12854. goto AbortAndExit;
  12855. }
  12856. RpcStatus = NewInChannel->Send(InChannelSendContext);
  12857. if (RpcStatus != RPC_S_OK)
  12858. goto AbortAndExit;
  12859. // we don't own this buffer now
  12860. InChannelSendContext = NULL;
  12861. }
  12862. if (SendOutChannel)
  12863. {
  12864. // should not happen during replacement
  12865. ASSERT(IsReplacementChannel == FALSE);
  12866. OutChannelSendContext = AllocateAndInitializeD1_A1(HTTP2ProtocolVersion,
  12867. &EmbeddedConnectionCookie,
  12868. &OutChannelCookies[0],
  12869. HTTP2DefaultClientReceiveWindow
  12870. );
  12871. if (OutChannelSendContext == NULL)
  12872. {
  12873. RpcStatus = RPC_S_OUT_OF_MEMORY;
  12874. goto AbortAndExit;
  12875. }
  12876. RpcStatus = NewOutChannel->Send(OutChannelSendContext);
  12877. if (RpcStatus != RPC_S_OK)
  12878. goto AbortAndExit;
  12879. // we don't own this buffer anymore
  12880. OutChannelSendContext = NULL;
  12881. }
  12882. // post receives on both channels
  12883. if (ReceiveOutChannel)
  12884. {
  12885. RpcStatus = NewOutChannel->Receive(http2ttRTS);
  12886. if (RpcStatus != RPC_S_OK)
  12887. {
  12888. goto AbortAndExit;
  12889. }
  12890. }
  12891. if (ReceiveInChannel)
  12892. {
  12893. RpcStatus = NewInChannel->Receive(http2ttRaw);
  12894. if (RpcStatus != RPC_S_OK)
  12895. goto AbortAndExit;
  12896. }
  12897. if (ResetInChannel || OpenInChannel || SendInChannel)
  12898. {
  12899. ASSERT(InChannelLocked);
  12900. InChannelPtr->UnlockChannelPointer();
  12901. InChannelLocked = FALSE;
  12902. // channel is unlocked. Can't touch it
  12903. NewInChannel = NULL;
  12904. }
  12905. if (ResetOutChannel || OpenOutChannel || SendOutChannel)
  12906. {
  12907. ASSERT(OutChannelLocked);
  12908. OutChannelPtr->UnlockChannelPointer();
  12909. OutChannelLocked = FALSE;
  12910. // channel is unlocked. Can't touch it
  12911. NewOutChannel = NULL;
  12912. }
  12913. if (IsDone)
  12914. {
  12915. RpcStatus = RPC_S_OK;
  12916. break;
  12917. }
  12918. // no authentication and single leg authentication are
  12919. // completed in one leg. Make sure we don't loop around
  12920. // with them for replacement case
  12921. if (ClientOpenInChannel && IsReplacementChannel)
  12922. {
  12923. ASSERT(InOpenType != cotNoAuth);
  12924. ASSERT(InOpenType != cotSLAuth);
  12925. ASSERT(InOpenType != cotMLAuth2);
  12926. }
  12927. if (ClientOpenOutChannel && IsReplacementChannel)
  12928. {
  12929. ASSERT(OutOpenType != cotNoAuth);
  12930. ASSERT(OutOpenType != cotSLAuth);
  12931. ASSERT(OutOpenType != cotMLAuth2);
  12932. }
  12933. WaitAgain:
  12934. // wait for something to happen
  12935. WaitResult = WaitForSingleObject(LocalClientOpenEvent, CallTimeout);
  12936. if (WaitResult == WAIT_TIMEOUT)
  12937. {
  12938. RpcStatus = RPC_S_CALL_CANCELLED;
  12939. goto AbortAndExit;
  12940. }
  12941. ASSERT(WaitResult == WAIT_OBJECT_0);
  12942. // there is race where we could have picked up a channel's event
  12943. // after we waited (e.g. two channels completed immediately after each
  12944. // other). In such case, there wouldn't be anything on any channel - wait
  12945. // again. This race exists only if we do initial connect.
  12946. if (IsReplacementChannel == FALSE)
  12947. {
  12948. if ((InOpenStatus == ERROR_IO_PENDING)
  12949. && (OutOpenStatus == ERROR_IO_PENDING))
  12950. {
  12951. goto WaitAgain;
  12952. }
  12953. }
  12954. OldInOpenType = InOpenType;
  12955. OldOutOpenType = OutOpenType;
  12956. // analyze what happened
  12957. // If we are in a non-terminal state, check what transitions we
  12958. // need to make to a terminal state
  12959. if (ClientOpenOutChannel
  12960. &&
  12961. (
  12962. (OutOpenType == cotSearchProxy)
  12963. ||
  12964. (OutOpenType == cotUnknownAuth)
  12965. )
  12966. )
  12967. {
  12968. OldOpenType = OutOpenType;
  12969. // We can be here in 3 cases:
  12970. // 1. We're searching for a proxy during initial open
  12971. // 2. We don't know the auth type during initial open
  12972. // 3. We recycle the out channel with unknown auth type
  12973. // The events of interest are:
  12974. // 1. If we are in case 2, and the channel is still pending,
  12975. // skip the channel.
  12976. // 2. If we're in the remainder of case 2 or we're in 3, or
  12977. // (we're in 1 and the in channel is not positive yet and we
  12978. // have given it enough time to come in, and we have a positive
  12979. // response on this channel), the result is final.
  12980. // 3. In case 1, if this channel has a negative response, fall through
  12981. // to both channel check
  12982. // 4. In case 1, if the other channel has come in, fall through
  12983. // capture the out open status to get a consistent view of it in
  12984. // the ifs below
  12985. LocalOutOpenStatus = OutOpenStatus;
  12986. if (OutOpenType == cotSearchProxy)
  12987. {
  12988. ASSERT(IsReplacementChannel == FALSE);
  12989. CurrentCase = 1;
  12990. }
  12991. else if (IsReplacementChannel == FALSE)
  12992. {
  12993. ASSERT(OutOpenType == cotUnknownAuth);
  12994. CurrentCase = 2;
  12995. }
  12996. else
  12997. {
  12998. ASSERT(IsReplacementChannel);
  12999. ASSERT(OutOpenType == cotUnknownAuth);
  13000. CurrentCase = 3;
  13001. }
  13002. if ((CurrentCase == 2)
  13003. && (LocalOutOpenStatus == ERROR_IO_PENDING))
  13004. {
  13005. NukeOutChannel = FALSE;
  13006. RebuildOutChannel = FALSE;
  13007. ResetOutChannel = FALSE;
  13008. OpenOutChannel = FALSE;
  13009. ReceiveOutChannel = FALSE;
  13010. SendOutChannel = FALSE;
  13011. }
  13012. else if
  13013. (
  13014. (CurrentCase == 2)
  13015. ||
  13016. (CurrentCase == 3)
  13017. ||
  13018. (
  13019. // positive response on case 1
  13020. (CurrentCase == 1)
  13021. &&
  13022. (!IsInChannelPositiveWithWait())
  13023. &&
  13024. (
  13025. (LocalOutOpenStatus == RPC_S_OK)
  13026. ||
  13027. (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  13028. )
  13029. )
  13030. )
  13031. {
  13032. // We'll be here in 3 cases
  13033. // 1. We don't know the auth type during initial open and we have
  13034. // a response on the channel
  13035. // 2. We recycle the out channel with unknown auth type
  13036. // 3. We search for a proxy and this channel will be chosen
  13037. // the status is final
  13038. if ((LocalOutOpenStatus != RPC_S_OK)
  13039. && (LocalOutOpenStatus != RPC_P_AUTH_NEEDED))
  13040. {
  13041. RpcStatus = LocalOutOpenStatus;
  13042. goto AbortAndExit;
  13043. }
  13044. // In all cases the auth scheme is final for the new channel and we
  13045. // need to continue authentication
  13046. // if we haven't chosen a scheme yet, choose it now
  13047. if (OutChosenAuthScheme == 0)
  13048. {
  13049. OutChosenAuthScheme = GetOutChannelChosenScheme(IsReplacementChannel);
  13050. }
  13051. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  13052. {
  13053. // milti legged authentication implies keep alives
  13054. IsKeepAlive = TRUE;
  13055. OutOpenType = cotMLAuth;
  13056. // we need only reset, open, send and receive
  13057. NukeOutChannel = FALSE;
  13058. RebuildOutChannel = FALSE;
  13059. ResetOutChannel = TRUE;
  13060. OpenOutChannel = TRUE;
  13061. SendOutChannel = FALSE;
  13062. ReceiveOutChannel = TRUE;
  13063. }
  13064. else
  13065. {
  13066. // SSL always supports keep alives
  13067. if (HttpCredentials && HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  13068. IsKeepAlive = TRUE;
  13069. else
  13070. {
  13071. IsKeepAlive = IsOutChannelKeepAlive(IsReplacementChannel);
  13072. }
  13073. if (OutChosenAuthScheme)
  13074. OutOpenType = cotSLAuth;
  13075. else
  13076. OutOpenType = cotNoAuth;
  13077. if (IsKeepAlive)
  13078. {
  13079. // we need nuke, rebuild, open, send, receive
  13080. NukeOutChannel = FALSE;
  13081. RebuildOutChannel = FALSE;
  13082. ResetOutChannel = TRUE;
  13083. }
  13084. else
  13085. {
  13086. // we need nuke, rebuild, open, send, receive
  13087. NukeOutChannel = TRUE;
  13088. RebuildOutChannel = TRUE;
  13089. ResetOutChannel = FALSE;
  13090. }
  13091. OpenOutChannel = TRUE;
  13092. if (IsReplacementChannel)
  13093. {
  13094. ReceiveOutChannel = FALSE;
  13095. // should be done on next iteration
  13096. IsDone = TRUE;
  13097. }
  13098. else
  13099. {
  13100. SendOutChannel = TRUE;
  13101. ReceiveOutChannel = TRUE;
  13102. }
  13103. }
  13104. OutOpenStatus = ERROR_IO_PENDING;
  13105. if (InOpenType == cotSearchProxy)
  13106. {
  13107. // we need to nuke, rebuild, open, send, possibly receive in channel
  13108. NukeInChannel = TRUE;
  13109. RebuildInChannel = TRUE;
  13110. ResetInChannel = FALSE;
  13111. OpenInChannel = TRUE;
  13112. SendInChannel = FALSE;
  13113. ReceiveInChannel = TRUE;
  13114. // if we have already chosen an auth scheme, presumably
  13115. // because of RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME, set it
  13116. if (InChosenAuthScheme)
  13117. {
  13118. ASSERT(IsReplacementChannel == FALSE);
  13119. ASSERT(HttpCredentials);
  13120. ASSERT(HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME);
  13121. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  13122. InOpenType = cotMLAuth;
  13123. else
  13124. {
  13125. InOpenType = cotSLAuth;
  13126. SendInChannel = TRUE;
  13127. }
  13128. }
  13129. else
  13130. InOpenType = cotUnknownAuth;
  13131. StoredAccessType = rpcpatHTTPProxy;
  13132. Hint->AccessType = rpcpatHTTPProxy;
  13133. }
  13134. if (IsReplacementChannel == FALSE)
  13135. {
  13136. // change the connection and channel state
  13137. SetNewConnectionState = TRUE;
  13138. NewConnectionState = http2svA3W;
  13139. }
  13140. if ((OldOpenType == cotSearchProxy) || IsReplacementChannel)
  13141. continue;
  13142. else
  13143. {
  13144. // we were doing initial open with cotUnknownAuth
  13145. // fall through to the in channel handling code to see
  13146. // what is it up to
  13147. }
  13148. }
  13149. else
  13150. {
  13151. // events 3 and 4. We're searching for the proxy and
  13152. // either this channel came with a negative response or
  13153. // the other channel came in
  13154. ASSERT(CurrentCase == 1);
  13155. ASSERT(IsReplacementChannel == FALSE);
  13156. ASSERT(OutOpenType == cotSearchProxy);
  13157. ASSERT(
  13158. (
  13159. (LocalOutOpenStatus != RPC_S_OK)
  13160. &&
  13161. (LocalOutOpenStatus != RPC_P_AUTH_NEEDED)
  13162. )
  13163. ||
  13164. (
  13165. (InOpenStatus == RPC_S_OK)
  13166. ||
  13167. (InOpenStatus == RPC_P_AUTH_NEEDED)
  13168. )
  13169. );
  13170. // fall through to the in channel check
  13171. }
  13172. }
  13173. if (
  13174. ClientOpenInChannel
  13175. &&
  13176. (
  13177. (InOpenType == cotSearchProxy)
  13178. ||
  13179. (InOpenType == cotUnknownAuth)
  13180. )
  13181. )
  13182. {
  13183. OldOpenType = InOpenType;
  13184. // We can be here in 3 cases:
  13185. // 1. We do initial open and we search for proxy
  13186. // 2. We do initial open with unknown auth.
  13187. // 3. We do in channel recycling with unknown auth
  13188. // The events of interest are:
  13189. // 1. If the channel is still pending and we are in case 2,
  13190. // skip the channel.
  13191. // 2. If we're in case 3, or the remainder of 2, or (we're in 1 and
  13192. // the result is positive), the result is final.
  13193. // 3. If we're in case 1, and the result is negative, fall
  13194. // through below to both channels checks
  13195. if (InOpenType == cotSearchProxy)
  13196. {
  13197. ASSERT(IsReplacementChannel == FALSE);
  13198. CurrentCase = 1;
  13199. }
  13200. else if (IsReplacementChannel == FALSE)
  13201. {
  13202. ASSERT(InOpenType == cotUnknownAuth);
  13203. CurrentCase = 2;
  13204. }
  13205. else
  13206. {
  13207. ASSERT(IsReplacementChannel);
  13208. ASSERT(InOpenType == cotUnknownAuth);
  13209. CurrentCase = 3;
  13210. }
  13211. // capture the InOpenStatus to get a consistent view
  13212. LocalInOpenStatus = InOpenStatus;
  13213. if ((CurrentCase == 2) && (LocalInOpenStatus == ERROR_IO_PENDING))
  13214. {
  13215. NukeInChannel = FALSE;
  13216. RebuildInChannel = FALSE;
  13217. ResetInChannel = FALSE;
  13218. OpenInChannel = FALSE;
  13219. ReceiveInChannel = FALSE;
  13220. SendInChannel = FALSE;
  13221. // the wait must have been woken by the out channel. Loop around
  13222. continue;
  13223. }
  13224. else if
  13225. (
  13226. (CurrentCase == 2)
  13227. ||
  13228. (CurrentCase == 3)
  13229. ||
  13230. (
  13231. (CurrentCase == 1)
  13232. &&
  13233. (
  13234. (LocalInOpenStatus == RPC_S_OK)
  13235. ||
  13236. (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  13237. )
  13238. )
  13239. )
  13240. {
  13241. if ((LocalInOpenStatus != RPC_S_OK)
  13242. && (LocalInOpenStatus != RPC_P_AUTH_NEEDED))
  13243. {
  13244. RpcStatus = LocalInOpenStatus;
  13245. goto AbortAndExit;
  13246. }
  13247. // if we haven't chosen a scheme yet, choose it now
  13248. if (InChosenAuthScheme == 0)
  13249. {
  13250. InChosenAuthScheme = GetInChannelChosenScheme(IsReplacementChannel);
  13251. }
  13252. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  13253. {
  13254. // milti legged authentication implies keep alives
  13255. IsKeepAlive = TRUE;
  13256. InOpenType = cotMLAuth;
  13257. // we need only reset, open, send and receive
  13258. NukeInChannel = FALSE;
  13259. RebuildInChannel = FALSE;
  13260. ResetInChannel = TRUE;
  13261. OpenInChannel = TRUE;
  13262. SendInChannel = FALSE;
  13263. ReceiveInChannel = TRUE;
  13264. }
  13265. else
  13266. {
  13267. // SSL always supports keep alives
  13268. if (HttpCredentials && HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  13269. IsKeepAlive = TRUE;
  13270. else
  13271. {
  13272. IsKeepAlive = IsInChannelKeepAlive(IsReplacementChannel);
  13273. }
  13274. if (InChosenAuthScheme)
  13275. InOpenType = cotSLAuth;
  13276. else
  13277. InOpenType = cotNoAuth;
  13278. if (IsKeepAlive)
  13279. {
  13280. // we need nuke, rebuild, open, send, receive
  13281. NukeInChannel = FALSE;
  13282. RebuildInChannel = FALSE;
  13283. ResetInChannel = TRUE;
  13284. }
  13285. else
  13286. {
  13287. // we need nuke, rebuild, open, send, receive
  13288. NukeInChannel = TRUE;
  13289. RebuildInChannel = TRUE;
  13290. ResetInChannel = FALSE;
  13291. }
  13292. OpenInChannel = TRUE;
  13293. if (IsReplacementChannel)
  13294. IsDone = TRUE;
  13295. else
  13296. SendInChannel = TRUE;
  13297. if (UseWinHttp || (IsReplacementChannel == FALSE))
  13298. ReceiveInChannel = FALSE;
  13299. else
  13300. ReceiveInChannel = TRUE;
  13301. }
  13302. InOpenStatus = ERROR_IO_PENDING;
  13303. if (OutOpenType == cotSearchProxy)
  13304. {
  13305. // we need to nuke, rebuild, open, send, possibly receive in channel
  13306. NukeOutChannel = TRUE;
  13307. RebuildOutChannel = TRUE;
  13308. ResetOutChannel = FALSE;
  13309. OpenOutChannel = TRUE;
  13310. SendOutChannel = FALSE;
  13311. ReceiveOutChannel = TRUE;
  13312. // if we have already chosen an auth scheme, presumably
  13313. // because of RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME, set it
  13314. if (OutChosenAuthScheme)
  13315. {
  13316. ASSERT(IsReplacementChannel == FALSE);
  13317. ASSERT(HttpCredentials);
  13318. ASSERT(HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME);
  13319. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  13320. OutOpenType = cotMLAuth;
  13321. else
  13322. {
  13323. OutOpenType = cotSLAuth;
  13324. SendOutChannel = TRUE;
  13325. }
  13326. }
  13327. else
  13328. OutOpenType = cotUnknownAuth;
  13329. StoredAccessType = rpcpatDirect;
  13330. Hint->AccessType = rpcpatDirect;
  13331. }
  13332. if (IsReplacementChannel == FALSE)
  13333. {
  13334. // change the connection and channel state
  13335. SetNewConnectionState = TRUE;
  13336. NewConnectionState = http2svA3W;
  13337. }
  13338. if ((OldOpenType == cotSearchProxy) || IsReplacementChannel)
  13339. continue;
  13340. else
  13341. {
  13342. // fall through to code that handles both channels
  13343. }
  13344. }
  13345. else
  13346. {
  13347. ASSERT(CurrentCase == 1);
  13348. ASSERT((LocalInOpenStatus != RPC_S_OK)
  13349. && (LocalInOpenStatus != RPC_P_AUTH_NEEDED) );
  13350. // fall through below
  13351. }
  13352. }
  13353. // did we get to an opened state? This should be checked only
  13354. // when we open both (initial open).
  13355. if ((IsReplacementChannel == FALSE)
  13356. && (InChannelState.State == http2svOpened))
  13357. {
  13358. RpcStatus = RPC_S_OK;
  13359. ASSERT(InChannelState.State == http2svOpened);
  13360. ASSERT(OutChannelState.State == http2svOpened);
  13361. RpcStatus = HTTP_CopyResolverHint(&ConnectionHint,
  13362. Hint,
  13363. FALSE // SourceWillBeAbandoned
  13364. );
  13365. if (RpcStatus != RPC_S_OK)
  13366. goto AbortAndExit;
  13367. break;
  13368. }
  13369. // if we are in a non-transitional state and we're doing an
  13370. // initial open, this means one of the channels didn't come in.
  13371. // Loop around
  13372. if ((IsReplacementChannel == FALSE)
  13373. && (
  13374. (InOpenType == cotUnknownAuth)
  13375. ||
  13376. (OutOpenType == cotUnknownAuth)
  13377. )
  13378. )
  13379. {
  13380. ASSERT((LocalInOpenStatus == ERROR_IO_PENDING)
  13381. || (LocalOutOpenStatus == ERROR_IO_PENDING));
  13382. continue;
  13383. }
  13384. // we're probably authenticating the individual channels
  13385. // see which channel is actionable and what to do with it
  13386. if (ClientOpenInChannel && (OldInOpenType == cotMLAuth))
  13387. {
  13388. // capture the InOpenStatus in a local variable for consistent
  13389. // view
  13390. LocalInOpenStatus = InOpenStatus;
  13391. if (LocalInOpenStatus != ERROR_IO_PENDING)
  13392. {
  13393. // something happened on the in channel. Process it
  13394. if (LocalInOpenStatus == RPC_S_OK)
  13395. {
  13396. // we have successfully completed
  13397. // authentication. Open the connection on the RTS
  13398. // level
  13399. InOpenStatus = ERROR_IO_PENDING;
  13400. // we need to reset, open, send, receive out channel
  13401. NukeInChannel = FALSE;
  13402. RebuildInChannel = FALSE;
  13403. ResetInChannel = TRUE;
  13404. OpenInChannel = TRUE;
  13405. ReceiveInChannel = FALSE;
  13406. if (IsReplacementChannel)
  13407. {
  13408. SendInChannel = FALSE;
  13409. IsDone = TRUE;
  13410. }
  13411. else
  13412. SendInChannel = TRUE;
  13413. InOpenType = cotMLAuth2;
  13414. }
  13415. else
  13416. {
  13417. // if after all the auth we still get a challenge, this means
  13418. // we couldn't auth and this is access denied.
  13419. if (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  13420. RpcStatus = RPC_S_ACCESS_DENIED;
  13421. else
  13422. RpcStatus = LocalInOpenStatus;
  13423. goto AbortAndExit;
  13424. }
  13425. }
  13426. else
  13427. {
  13428. // fall through. Below we will detect the state
  13429. // hasn't changed and we won't do any operations
  13430. // on this channel
  13431. }
  13432. }
  13433. if (ClientOpenOutChannel && (OldOutOpenType == cotMLAuth))
  13434. {
  13435. // capture the OutOpenStatus in a local variable for consistent
  13436. // view
  13437. LocalOutOpenStatus = OutOpenStatus;
  13438. if (LocalOutOpenStatus != ERROR_IO_PENDING)
  13439. {
  13440. // something happened on the in channel. Process it
  13441. if (LocalOutOpenStatus == RPC_S_OK)
  13442. {
  13443. // we have successfully completed multi-legged
  13444. // authentication. Open the connection on the RTS
  13445. // level
  13446. OutOpenStatus = ERROR_IO_PENDING;
  13447. // we need to reset, open, send, receive out channel
  13448. NukeOutChannel = FALSE;
  13449. RebuildOutChannel = FALSE;
  13450. ResetOutChannel = TRUE;
  13451. OpenOutChannel = TRUE;
  13452. if (IsReplacementChannel)
  13453. {
  13454. ReceiveOutChannel = FALSE;
  13455. SendOutChannel = FALSE;
  13456. IsDone = TRUE;
  13457. }
  13458. else
  13459. {
  13460. ReceiveOutChannel = TRUE;
  13461. SendOutChannel = TRUE;
  13462. }
  13463. OutOpenType = cotMLAuth2;
  13464. }
  13465. else
  13466. {
  13467. // if after all the auth we still get a challenge, this means
  13468. // we couldn't auth and this is access denied.
  13469. if (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  13470. RpcStatus = RPC_S_ACCESS_DENIED;
  13471. else
  13472. RpcStatus = LocalOutOpenStatus;
  13473. goto AbortAndExit;
  13474. }
  13475. }
  13476. else
  13477. {
  13478. // fall through. Below we will detect the state
  13479. // hasn't changed and we won't do any operations
  13480. // on this channel
  13481. }
  13482. }
  13483. if ((IsReplacementChannel == FALSE) && (InOpenType == cotSearchProxy))
  13484. {
  13485. // none of the channels came in positive so far. If at least one
  13486. // is still pending, wait for it
  13487. if ((LocalInOpenStatus == ERROR_IO_PENDING)
  13488. || (LocalOutOpenStatus == ERROR_IO_PENDING))
  13489. {
  13490. #if DBG_ERROR
  13491. DbgPrint("Waiting again ....\n");
  13492. #endif
  13493. goto WaitAgain;
  13494. }
  13495. // both channels came in negative. The server is not
  13496. // available
  13497. if ((LocalInOpenStatus == RPC_S_ACCESS_DENIED)
  13498. || (LocalOutOpenStatus == RPC_S_ACCESS_DENIED))
  13499. RpcStatus = RPC_S_ACCESS_DENIED;
  13500. else
  13501. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  13502. goto AbortAndExit;
  13503. }
  13504. // if we came in with a terminal state and the server responded
  13505. // with an error, bail out
  13506. // first, capture the InOpenStatus in a local variable for consistent
  13507. // view
  13508. LocalInOpenStatus = InOpenStatus;
  13509. if (ClientOpenInChannel
  13510. &&
  13511. (
  13512. (OldInOpenType == cotSLAuth)
  13513. ||
  13514. (OldInOpenType == cotNoAuth)
  13515. ||
  13516. (OldInOpenType == cotMLAuth2)
  13517. )
  13518. &&
  13519. (LocalInOpenStatus != RPC_S_OK)
  13520. &&
  13521. (LocalInOpenStatus != ERROR_IO_PENDING)
  13522. )
  13523. {
  13524. if (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  13525. RpcStatus = RPC_S_ACCESS_DENIED;
  13526. else
  13527. RpcStatus = LocalInOpenStatus;
  13528. goto AbortAndExit;
  13529. }
  13530. // capture the OutOpenStatus in a local variable for consistent
  13531. // view
  13532. LocalOutOpenStatus = OutOpenStatus;
  13533. if (ClientOpenOutChannel
  13534. &&
  13535. (
  13536. (OldOutOpenType == cotSLAuth)
  13537. ||
  13538. (OldOutOpenType == cotNoAuth)
  13539. ||
  13540. (OldOutOpenType == cotMLAuth2)
  13541. )
  13542. &&
  13543. (LocalOutOpenStatus != RPC_S_OK)
  13544. &&
  13545. (LocalOutOpenStatus != ERROR_IO_PENDING)
  13546. )
  13547. {
  13548. if (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  13549. RpcStatus = RPC_S_ACCESS_DENIED;
  13550. else
  13551. RpcStatus = LocalOutOpenStatus;
  13552. goto AbortAndExit;
  13553. }
  13554. // if state hasn't changed, don't do anything on this channel
  13555. if (OldInOpenType == InOpenType)
  13556. {
  13557. NukeInChannel = FALSE;
  13558. RebuildInChannel = FALSE;
  13559. ResetInChannel = FALSE;
  13560. OpenInChannel = FALSE;
  13561. ReceiveInChannel = FALSE;
  13562. SendInChannel = FALSE;
  13563. }
  13564. if (OldOutOpenType == OutOpenType)
  13565. {
  13566. NukeOutChannel = FALSE;
  13567. RebuildOutChannel = FALSE;
  13568. ResetOutChannel = FALSE;
  13569. OpenOutChannel = FALSE;
  13570. ReceiveOutChannel = FALSE;
  13571. SendOutChannel = FALSE;
  13572. }
  13573. // loop around for further processing
  13574. }
  13575. IgnoreAborts = FALSE;
  13576. ASSERT(RpcStatus == RPC_S_OK);
  13577. if (IsReplacementChannel == FALSE)
  13578. {
  13579. ASSERT(InChannelState.State == http2svOpened);
  13580. }
  13581. ASSERT(LocalClientOpenEvent);
  13582. InChannelState.Mutex.Request();
  13583. ClientOpenInEvent = NULL;
  13584. ClientOpenOutEvent = NULL;
  13585. InChannelState.Mutex.Clear();
  13586. CloseHandle(LocalClientOpenEvent);
  13587. return RpcStatus;
  13588. AbortAndExit:
  13589. if (InChannelLocked)
  13590. {
  13591. InChannelPtr->UnlockChannelPointer();
  13592. }
  13593. if (OutChannelLocked)
  13594. {
  13595. OutChannelPtr->UnlockChannelPointer();
  13596. }
  13597. if (InChannelSendContext)
  13598. {
  13599. FreeRTSPacket(InChannelSendContext);
  13600. }
  13601. if (OutChannelSendContext)
  13602. {
  13603. FreeRTSPacket(OutChannelSendContext);
  13604. }
  13605. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  13606. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  13607. || (RpcStatus == RPC_P_SEND_FAILED))
  13608. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  13609. else if ((RpcStatus == RPC_P_RECEIVE_FAILED) && IsReplacementChannel)
  13610. {
  13611. // RPC_P_RECEIVE_FAILED is also mapped to server unavailable, but only
  13612. // during channel recycling. The reason is that the old crappy RPC Proxy
  13613. // will just close the connection if we directly access the RPC Proxy,
  13614. // so all that we will get will be RPC_P_RECEIVE_FAILED. Not mapping it
  13615. // during initial conneciton establishment allows upper layers to try the old
  13616. // HTTP thus preserving interop
  13617. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  13618. }
  13619. ASSERT(LocalClientOpenEvent);
  13620. InChannelState.Mutex.Request();
  13621. ClientOpenInEvent = NULL;
  13622. ClientOpenOutEvent = NULL;
  13623. InChannelState.Mutex.Clear();
  13624. CloseHandle(LocalClientOpenEvent);
  13625. VALIDATE (RpcStatus)
  13626. {
  13627. RPC_S_PROTSEQ_NOT_SUPPORTED,
  13628. RPC_S_SERVER_UNAVAILABLE,
  13629. RPC_S_OUT_OF_MEMORY,
  13630. RPC_S_OUT_OF_RESOURCES,
  13631. RPC_S_SERVER_TOO_BUSY,
  13632. RPC_S_INVALID_NETWORK_OPTIONS,
  13633. RPC_S_INVALID_ENDPOINT_FORMAT,
  13634. RPC_S_INVALID_NET_ADDR,
  13635. RPC_S_ACCESS_DENIED,
  13636. RPC_S_INTERNAL_ERROR,
  13637. RPC_S_SERVER_OUT_OF_MEMORY,
  13638. RPC_S_CALL_CANCELLED,
  13639. RPC_S_PROTOCOL_ERROR,
  13640. RPC_P_RECEIVE_FAILED
  13641. } END_VALIDATE;
  13642. IgnoreAborts = FALSE;
  13643. // If we are not from upcall, abort. Else, caller will
  13644. // abort
  13645. if (IsFromUpcall == FALSE)
  13646. Abort();
  13647. return RpcStatus;
  13648. }
  13649. RPC_STATUS HTTP2ClientVirtualConnection::AllocateAndInitializeInChannel (
  13650. IN HTTPResolverHint *Hint,
  13651. IN BOOL HintWasInitialized,
  13652. IN ULONG CallTimeout,
  13653. IN BOOL UseWinHttp,
  13654. OUT HTTP2ClientInChannel **ReturnInChannel
  13655. )
  13656. /*++
  13657. Routine Description:
  13658. Allocate and initialize the in channel stack
  13659. Arguments:
  13660. Hint - the resolver hint
  13661. HintWasInitialized - true if the hint was initialized on input
  13662. CallTimeout - the timeout for the operation
  13663. ReturnInChannel - on success the pointer to the allocated in channel.
  13664. Undefined on failure.
  13665. UseWinHttp - non-zero if WinHttp should be used for the bottom channel.
  13666. Return Value:
  13667. RPC_S_OK or other RPC_S_* errors for error
  13668. --*/
  13669. {
  13670. ULONG MemorySize;
  13671. BYTE *MemoryBlock, *CurrentBlock;
  13672. HTTP2ClientInChannel *InChannel;
  13673. HTTP2PlugChannel *PlugChannel;
  13674. HTTP2FlowControlSender *FlowControlSender;
  13675. HTTP2PingOriginator *PingOriginator;
  13676. HTTP2ChannelDataOriginator *ChannelDataOriginator;
  13677. HTTP2SocketTransportChannel *RawChannel;
  13678. WS_HTTP2_CONNECTION *RawConnection;
  13679. HTTP2WinHttpTransportChannel *WinHttpConnection;
  13680. BOOL PlugChannelNeedsCleanup;
  13681. BOOL FlowControlSenderNeedsCleanup;
  13682. BOOL PingOriginatorNeedsCleanup;
  13683. BOOL ChannelDataOriginatorNeedsCleanup;
  13684. BOOL RawChannelNeedsCleanup;
  13685. BOOL RawConnectionNeedsCleanup;
  13686. BOOL WinHttpConnectionNeedsCleanup;
  13687. RPC_STATUS RpcStatus;
  13688. // alocate the in channel
  13689. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientInChannel)
  13690. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel)
  13691. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  13692. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator)
  13693. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator)
  13694. ;
  13695. if (UseWinHttp)
  13696. MemorySize += sizeof(HTTP2WinHttpTransportChannel);
  13697. else
  13698. {
  13699. MemorySize += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  13700. + sizeof(WS_HTTP2_CONNECTION);
  13701. }
  13702. CurrentBlock = MemoryBlock = (BYTE *) new char [MemorySize];
  13703. if (CurrentBlock == NULL)
  13704. return RPC_S_OUT_OF_MEMORY;
  13705. InChannel = (HTTP2ClientInChannel *) MemoryBlock;
  13706. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientInChannel);
  13707. PlugChannel = (HTTP2PlugChannel *) CurrentBlock;
  13708. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel);
  13709. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  13710. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  13711. PingOriginator = (HTTP2PingOriginator *)CurrentBlock;
  13712. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator);
  13713. ChannelDataOriginator = (HTTP2ChannelDataOriginator *)CurrentBlock;
  13714. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator);
  13715. if (UseWinHttp)
  13716. {
  13717. WinHttpConnection = (HTTP2WinHttpTransportChannel *)CurrentBlock;
  13718. }
  13719. else
  13720. {
  13721. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  13722. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  13723. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  13724. RawConnection->HeaderRead = FALSE;
  13725. RawConnection->ReadHeaderFn = HTTP2ClientReadChannelHeader;
  13726. }
  13727. // all memory blocks are allocated. Go and initialize them. Use explicit
  13728. // placement
  13729. PlugChannelNeedsCleanup = FALSE;
  13730. FlowControlSenderNeedsCleanup = FALSE;
  13731. PingOriginatorNeedsCleanup = FALSE;
  13732. ChannelDataOriginatorNeedsCleanup = FALSE;
  13733. RawChannelNeedsCleanup = FALSE;
  13734. RawConnectionNeedsCleanup = FALSE;
  13735. WinHttpConnectionNeedsCleanup = FALSE;
  13736. if (UseWinHttp)
  13737. {
  13738. RpcStatus = RPC_S_OK;
  13739. WinHttpConnection = new (WinHttpConnection) HTTP2WinHttpTransportChannel (&RpcStatus);
  13740. if (RpcStatus != RPC_S_OK)
  13741. {
  13742. WinHttpConnection->HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  13743. goto AbortAndExit;
  13744. }
  13745. WinHttpConnectionNeedsCleanup = TRUE;
  13746. }
  13747. else
  13748. {
  13749. RpcStatus = InitializeRawConnection (RawConnection,
  13750. Hint,
  13751. HintWasInitialized,
  13752. CallTimeout
  13753. );
  13754. if (RpcStatus != RPC_S_OK)
  13755. goto AbortAndExit;
  13756. RawConnection->RuntimeConnectionPtr = this;
  13757. RawConnectionNeedsCleanup = TRUE;
  13758. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  13759. if (RpcStatus != RPC_S_OK)
  13760. {
  13761. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  13762. goto AbortAndExit;
  13763. }
  13764. RawConnection->Channel = RawChannel;
  13765. RawChannelNeedsCleanup = TRUE;
  13766. }
  13767. ChannelDataOriginator = new (ChannelDataOriginator) HTTP2ChannelDataOriginator (DefaultChannelLifetime,
  13768. FALSE, // IsServer
  13769. &RpcStatus);
  13770. if (RpcStatus != RPC_S_OK)
  13771. {
  13772. ChannelDataOriginator->HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  13773. goto AbortAndExit;
  13774. }
  13775. if (UseWinHttp)
  13776. {
  13777. WinHttpConnection->SetUpperChannel(ChannelDataOriginator);
  13778. ChannelDataOriginator->SetLowerChannel(WinHttpConnection);
  13779. }
  13780. else
  13781. {
  13782. RawChannel->SetUpperChannel(ChannelDataOriginator);
  13783. ChannelDataOriginator->SetLowerChannel(RawChannel);
  13784. }
  13785. ChannelDataOriginatorNeedsCleanup = TRUE;
  13786. PingOriginator = new (PingOriginator) HTTP2PingOriginator (
  13787. FALSE // NotifyTopChannelForPings
  13788. );
  13789. ChannelDataOriginator->SetUpperChannel(PingOriginator);
  13790. PingOriginator->SetLowerChannel(ChannelDataOriginator);
  13791. PingOriginatorNeedsCleanup = TRUE;
  13792. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  13793. TRUE, // SendToRuntime
  13794. &RpcStatus
  13795. );
  13796. if (RpcStatus != RPC_S_OK)
  13797. {
  13798. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  13799. goto AbortAndExit;
  13800. }
  13801. PingOriginator->SetUpperChannel(FlowControlSender);
  13802. FlowControlSender->SetLowerChannel(PingOriginator);
  13803. FlowControlSenderNeedsCleanup = TRUE;
  13804. PlugChannel = new (PlugChannel) HTTP2PlugChannel (&RpcStatus);
  13805. if (RpcStatus != RPC_S_OK)
  13806. {
  13807. PlugChannel->HTTP2PlugChannel::~HTTP2PlugChannel();
  13808. goto AbortAndExit;
  13809. }
  13810. FlowControlSender->SetUpperChannel(PlugChannel);
  13811. PlugChannel->SetLowerChannel(FlowControlSender);
  13812. PlugChannelNeedsCleanup = TRUE;
  13813. InChannel = new (InChannel) HTTP2ClientInChannel (this, &RpcStatus);
  13814. if (RpcStatus != RPC_S_OK)
  13815. {
  13816. InChannel->HTTP2ClientInChannel::~HTTP2ClientInChannel();
  13817. goto AbortAndExit;
  13818. }
  13819. if (UseWinHttp)
  13820. WinHttpConnection->SetTopChannel(InChannel);
  13821. else
  13822. RawChannel->SetTopChannel(InChannel);
  13823. ChannelDataOriginator->SetTopChannel(InChannel);
  13824. PingOriginator->SetTopChannel(InChannel);
  13825. FlowControlSender->SetTopChannel(InChannel);
  13826. PlugChannel->SetTopChannel(InChannel);
  13827. PlugChannel->SetUpperChannel(InChannel);
  13828. InChannel->SetLowerChannel(PlugChannel);
  13829. ASSERT(RpcStatus == RPC_S_OK);
  13830. *ReturnInChannel = InChannel;
  13831. goto CleanupAndExit;
  13832. AbortAndExit:
  13833. if (PlugChannelNeedsCleanup)
  13834. {
  13835. PlugChannel->Abort(RpcStatus);
  13836. PlugChannel->FreeObject();
  13837. }
  13838. else if (FlowControlSenderNeedsCleanup)
  13839. {
  13840. FlowControlSender->Abort(RpcStatus);
  13841. FlowControlSender->FreeObject();
  13842. }
  13843. else if (PingOriginatorNeedsCleanup)
  13844. {
  13845. PingOriginator->Abort(RpcStatus);
  13846. PingOriginator->FreeObject();
  13847. }
  13848. else if (ChannelDataOriginatorNeedsCleanup)
  13849. {
  13850. ChannelDataOriginator->Abort(RpcStatus);
  13851. ChannelDataOriginator->FreeObject();
  13852. }
  13853. else if (UseWinHttp)
  13854. {
  13855. if (WinHttpConnectionNeedsCleanup)
  13856. {
  13857. WinHttpConnection->Abort(RpcStatus);
  13858. WinHttpConnection->FreeObject();
  13859. }
  13860. }
  13861. else if (RawChannelNeedsCleanup)
  13862. {
  13863. RawChannel->Abort(RpcStatus);
  13864. RawChannel->FreeObject();
  13865. }
  13866. else if (RawConnectionNeedsCleanup)
  13867. {
  13868. RawConnection->RealAbort();
  13869. }
  13870. if (MemoryBlock)
  13871. delete [] MemoryBlock;
  13872. CleanupAndExit:
  13873. return RpcStatus;
  13874. }
  13875. RPC_STATUS
  13876. RPC_ENTRY
  13877. HTTP2ReadHttpLegacyResponse (
  13878. IN WS_HTTP2_CONNECTION *Connection,
  13879. IN ULONG BytesRead,
  13880. OUT ULONG *NewBytesRead
  13881. )
  13882. /*++
  13883. Routine Description:
  13884. Read a channel HTTP header (usually some string). In success
  13885. case, there is real data in Connection->pReadBuffer. The
  13886. number of bytes there is in NewBytesRead
  13887. Arguments:
  13888. Connection - the connection on which the header arrived.
  13889. BytesRead - the bytes received from the net
  13890. NewBytesRead - the bytes read from the channel (success only)
  13891. Return Value:
  13892. RPC_S_OK or other RPC_S_* errors for error
  13893. RPC_P_PARTIAL_RECEIVE will cause another loop.
  13894. Any other error will cause processing of NewBuffer
  13895. --*/
  13896. {
  13897. RPC_STATUS RpcStatus;
  13898. BYTE *NewBuffer;
  13899. BytesRead += Connection->iLastRead;
  13900. // check whether what we have is a legacy response
  13901. // legacy response is ncacn_http/1.0
  13902. if (*(ULONG *)Connection->pReadBuffer == (ULONG)'cacn')
  13903. {
  13904. // Let's process it now.
  13905. // see if we have sufficient length
  13906. if (BytesRead < HTTP_SERVER_ID_STR_LEN)
  13907. {
  13908. Connection->iLastRead = BytesRead;
  13909. return RPC_P_PARTIAL_RECEIVE;
  13910. }
  13911. else if (BytesRead == HTTP_SERVER_ID_STR_LEN)
  13912. {
  13913. // reset the pointer. By doing so we forget all we have
  13914. // read so far
  13915. Connection->iLastRead = 0;
  13916. Connection->HeaderRead = TRUE;
  13917. return RPC_P_PARTIAL_RECEIVE;
  13918. }
  13919. else
  13920. {
  13921. // we have what we expect, and something more (coalesced read)
  13922. // Process it. First make sure it is what we expect
  13923. if (RpcpMemoryCompare(Connection->pReadBuffer, HTTP_SERVER_ID_STR, HTTP_SERVER_ID_STR_LEN) != 0)
  13924. {
  13925. return RPC_S_PROTOCOL_ERROR;
  13926. }
  13927. NewBuffer = TransConnectionAllocatePacket(Connection,
  13928. max(Connection->iPostSize, BytesRead - HTTP_SERVER_ID_STR_LEN));
  13929. if (0 == NewBuffer)
  13930. return RPC_S_OUT_OF_MEMORY;
  13931. RpcpMemoryCopy(NewBuffer,
  13932. ((BYTE *)Connection->pReadBuffer) + HTTP_SERVER_ID_STR_LEN,
  13933. BytesRead - HTTP_SERVER_ID_STR_LEN);
  13934. *NewBytesRead = BytesRead - HTTP_SERVER_ID_STR_LEN;
  13935. RpcFreeBuffer(Connection->pReadBuffer);
  13936. Connection->pReadBuffer = NewBuffer;
  13937. Connection->iLastRead = 0;
  13938. Connection->HeaderRead = TRUE;
  13939. return RPC_S_OK;
  13940. }
  13941. }
  13942. else
  13943. {
  13944. *NewBytesRead = BytesRead;
  13945. Connection->iLastRead = 0;
  13946. Connection->HeaderRead = TRUE;
  13947. return RPC_S_OK;
  13948. }
  13949. }
  13950. RPC_STATUS HTTP2ClientVirtualConnection::AllocateAndInitializeOutChannel (
  13951. IN HTTPResolverHint *Hint,
  13952. IN BOOL HintWasInitialized,
  13953. IN ULONG CallTimeout,
  13954. IN BOOL UseWinHttp,
  13955. OUT HTTP2ClientOutChannel **ReturnOutChannel
  13956. )
  13957. /*++
  13958. Routine Description:
  13959. Allocate and initialize the out channel stack
  13960. Arguments:
  13961. Hint - the resolver hint
  13962. HintWasInitialized - true if the hint was initialized on input
  13963. CallTimeout - the timeout for the operation
  13964. ReturnInChannel - on success the pointer to the allocated in channel.
  13965. Undefined on failure.
  13966. UseWinHttp - non-zero if WinHttp should be used for the bottom channel.
  13967. Return Value:
  13968. RPC_S_OK or other RPC_S_* errors for error
  13969. --*/
  13970. {
  13971. ULONG MemorySize;
  13972. BYTE *MemoryBlock, *CurrentBlock;
  13973. HTTP2ClientOutChannel *OutChannel;
  13974. HTTP2EndpointReceiver *EndpointReceiver;
  13975. HTTP2PingReceiver *PingReceiver;
  13976. HTTP2SocketTransportChannel *RawChannel;
  13977. WS_HTTP2_CONNECTION *RawConnection;
  13978. HTTP2WinHttpTransportChannel *WinHttpConnection;
  13979. BOOL EndpointReceiverNeedsCleanup;
  13980. BOOL PingReceiverNeedsCleanup;
  13981. BOOL RawChannelNeedsCleanup;
  13982. BOOL RawConnectionNeedsCleanup;
  13983. BOOL WinHttpConnectionNeedsCleanup;
  13984. RPC_STATUS RpcStatus;
  13985. // alocate the out channel
  13986. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientOutChannel)
  13987. + SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver)
  13988. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  13989. ;
  13990. if (UseWinHttp)
  13991. MemorySize += sizeof(HTTP2WinHttpTransportChannel);
  13992. else
  13993. {
  13994. MemorySize += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  13995. + sizeof(WS_HTTP2_CONNECTION);
  13996. }
  13997. CurrentBlock = MemoryBlock = (BYTE *) new char [MemorySize];
  13998. if (CurrentBlock == NULL)
  13999. return RPC_S_OUT_OF_MEMORY;
  14000. OutChannel = (HTTP2ClientOutChannel *) MemoryBlock;
  14001. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientOutChannel);
  14002. EndpointReceiver = (HTTP2EndpointReceiver *)CurrentBlock;
  14003. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver);
  14004. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  14005. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  14006. if (UseWinHttp)
  14007. {
  14008. WinHttpConnection = (HTTP2WinHttpTransportChannel *)CurrentBlock;
  14009. }
  14010. else
  14011. {
  14012. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  14013. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  14014. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  14015. RawConnection->HeaderRead = FALSE;
  14016. RawConnection->ReadHeaderFn = HTTP2ClientReadChannelHeader;
  14017. }
  14018. // all memory blocks are allocated. Go and initialize them. Use explicit
  14019. // placement
  14020. EndpointReceiverNeedsCleanup = FALSE;
  14021. PingReceiverNeedsCleanup = FALSE;
  14022. RawChannelNeedsCleanup = FALSE;
  14023. RawConnectionNeedsCleanup = FALSE;
  14024. WinHttpConnectionNeedsCleanup = FALSE;
  14025. if (UseWinHttp)
  14026. {
  14027. RpcStatus = RPC_S_OK;
  14028. WinHttpConnection = new (WinHttpConnection) HTTP2WinHttpTransportChannel (&RpcStatus);
  14029. if (RpcStatus != RPC_S_OK)
  14030. {
  14031. WinHttpConnection->HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  14032. goto AbortAndExit;
  14033. }
  14034. WinHttpConnectionNeedsCleanup = TRUE;
  14035. }
  14036. else
  14037. {
  14038. RpcStatus = InitializeRawConnection (RawConnection,
  14039. Hint,
  14040. HintWasInitialized,
  14041. CallTimeout
  14042. );
  14043. if (RpcStatus != RPC_S_OK)
  14044. goto AbortAndExit;
  14045. RawConnection->RuntimeConnectionPtr = this;
  14046. RawConnectionNeedsCleanup = TRUE;
  14047. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  14048. if (RpcStatus != RPC_S_OK)
  14049. {
  14050. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  14051. goto AbortAndExit;
  14052. }
  14053. RawConnection->Channel = RawChannel;
  14054. RawChannelNeedsCleanup = TRUE;
  14055. }
  14056. PingReceiver = new (PingReceiver) HTTP2PingReceiver(TRUE);
  14057. if (UseWinHttp)
  14058. {
  14059. WinHttpConnection->SetUpperChannel(PingReceiver);
  14060. PingReceiver->SetLowerChannel(WinHttpConnection);
  14061. }
  14062. else
  14063. {
  14064. RawChannel->SetUpperChannel(PingReceiver);
  14065. PingReceiver->SetLowerChannel(RawChannel);
  14066. }
  14067. PingReceiverNeedsCleanup = TRUE;
  14068. EndpointReceiver = new (EndpointReceiver) HTTP2EndpointReceiver(HTTP2ClientReceiveWindow,
  14069. FALSE, // IsServer
  14070. &RpcStatus);
  14071. if (RpcStatus != RPC_S_OK)
  14072. {
  14073. EndpointReceiver->HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  14074. goto AbortAndExit;
  14075. }
  14076. PingReceiver->SetUpperChannel(EndpointReceiver);
  14077. EndpointReceiver->SetLowerChannel(PingReceiver);
  14078. EndpointReceiverNeedsCleanup = TRUE;
  14079. OutChannel = new (OutChannel) HTTP2ClientOutChannel (this, &RpcStatus);
  14080. if (RpcStatus != RPC_S_OK)
  14081. {
  14082. OutChannel->HTTP2ClientOutChannel::~HTTP2ClientOutChannel();
  14083. goto AbortAndExit;
  14084. }
  14085. EndpointReceiver->SetUpperChannel(OutChannel);
  14086. OutChannel->SetLowerChannel(EndpointReceiver);
  14087. if (UseWinHttp)
  14088. WinHttpConnection->SetTopChannel(OutChannel);
  14089. else
  14090. RawChannel->SetTopChannel(OutChannel);
  14091. PingReceiver->SetTopChannel(OutChannel);
  14092. EndpointReceiver->SetTopChannel(OutChannel);
  14093. ASSERT(RpcStatus == RPC_S_OK);
  14094. *ReturnOutChannel = OutChannel;
  14095. goto CleanupAndExit;
  14096. AbortAndExit:
  14097. if (EndpointReceiverNeedsCleanup)
  14098. {
  14099. EndpointReceiver->Abort(RpcStatus);
  14100. EndpointReceiver->FreeObject();
  14101. }
  14102. else if (PingReceiverNeedsCleanup)
  14103. {
  14104. PingReceiver->Abort(RpcStatus);
  14105. PingReceiver->FreeObject();
  14106. }
  14107. else if (UseWinHttp)
  14108. {
  14109. if (WinHttpConnectionNeedsCleanup)
  14110. {
  14111. WinHttpConnection->Abort(RpcStatus);
  14112. WinHttpConnection->FreeObject();
  14113. }
  14114. }
  14115. else if (RawChannelNeedsCleanup)
  14116. {
  14117. RawChannel->Abort(RpcStatus);
  14118. RawChannel->FreeObject();
  14119. }
  14120. else if (RawConnectionNeedsCleanup)
  14121. {
  14122. RawConnection->RealAbort();
  14123. }
  14124. if (MemoryBlock)
  14125. delete [] MemoryBlock;
  14126. CleanupAndExit:
  14127. return RpcStatus;
  14128. }
  14129. RPC_STATUS HTTP2ClientVirtualConnection::InitializeRawConnection (
  14130. IN OUT WS_HTTP2_CONNECTION *RawConnection,
  14131. IN HTTPResolverHint *Hint,
  14132. IN BOOL HintWasInitialized,
  14133. IN ULONG CallTimeout
  14134. )
  14135. /*++
  14136. Routine Description:
  14137. Initialize a raw client connection
  14138. Arguments:
  14139. RawConnection - memory for the connection. It is uninitialized
  14140. Hint - the resolver hint
  14141. HintWasInitialized - true if the hint was initialized on input
  14142. CallTimeout - the timeout for the operation
  14143. Return Value:
  14144. RPC_S_OK or other RPC_S_* errors for error
  14145. --*/
  14146. {
  14147. RPC_STATUS RpcStatus;
  14148. RPC_CHAR *ConnectionTargetName;
  14149. USHORT PortToUse;
  14150. RawConnection->Initialize();
  14151. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  14152. // initialize raw connection
  14153. if (Hint->AccessType == rpcpatHTTPProxy)
  14154. {
  14155. ConnectionTargetName = new RPC_CHAR [RpcpStringLengthA(Hint->HTTPProxy) + 2];
  14156. if (ConnectionTargetName == NULL)
  14157. {
  14158. RpcStatus = RPC_S_OUT_OF_MEMORY;
  14159. return RpcStatus;
  14160. }
  14161. FullAnsiToUnicode(Hint->HTTPProxy, ConnectionTargetName);
  14162. PortToUse = Hint->HTTPProxyPort;
  14163. }
  14164. else
  14165. {
  14166. ASSERT(Hint->AccessType == rpcpatDirect);
  14167. ConnectionTargetName = new RPC_CHAR [RpcpStringLengthA(Hint->RpcProxy) + 1];
  14168. if (ConnectionTargetName == NULL)
  14169. {
  14170. RpcStatus = RPC_S_OUT_OF_MEMORY;
  14171. return RpcStatus;
  14172. }
  14173. FullAnsiToUnicode(Hint->RpcProxy, ConnectionTargetName);
  14174. PortToUse = Hint->RpcProxyPort;
  14175. }
  14176. RpcStatus = TCPOrHTTP_Open(RawConnection,
  14177. ConnectionTargetName,
  14178. PortToUse,
  14179. ConnectionTimeout,
  14180. 0, // SendBufferSize
  14181. 0, // RecvBufferSize
  14182. Hint,
  14183. HintWasInitialized,
  14184. CallTimeout,
  14185. TRUE, // fHTTP2Open
  14186. NULL // IsValidMachineFn
  14187. );
  14188. delete [] ConnectionTargetName;
  14189. return RpcStatus;
  14190. }
  14191. BOOL HTTP2ClientVirtualConnection::IsInChannelKeepAlive (
  14192. IN BOOL IsReplacementChannel
  14193. )
  14194. /*++
  14195. Routine Description:
  14196. Checks whether the an in channel supports keep alives.
  14197. Which channel depends on the arguments - see below.
  14198. Arguments:
  14199. IsReplacementInChannel - if non-zero, this is a replacement
  14200. channel and the non-default channel will be checked. If 0,
  14201. this is a first channel, and the zero'th channel will be
  14202. checked.
  14203. Return Value:
  14204. non-zero - the channel supports keep alives
  14205. 0 - the channel doesn't support keep alives
  14206. --*/
  14207. {
  14208. HTTP2ClientInChannel *InChannel;
  14209. BOOL IsKeepAlive;
  14210. HTTP2ChannelPointer *InChannelPtr;
  14211. if (IsReplacementChannel)
  14212. InChannelPtr = &InChannels[GetNonDefaultInChannelSelector()];
  14213. else
  14214. InChannelPtr = &InChannels[0];
  14215. InChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  14216. // nobody can abort the connection here
  14217. ASSERT (InChannel != NULL);
  14218. IsKeepAlive = InChannel->IsKeepAlive();
  14219. InChannelPtr->UnlockChannelPointer();
  14220. return IsKeepAlive;
  14221. }
  14222. BOOL HTTP2ClientVirtualConnection::IsOutChannelKeepAlive (
  14223. IN BOOL IsReplacementChannel
  14224. )
  14225. /*++
  14226. Routine Description:
  14227. Checks whether an out channel supports keep alives
  14228. Which channel depends on the arguments - see below.
  14229. Arguments:
  14230. IsReplacementInChannel - if non-zero, this is a replacement
  14231. channel and the non-default channel will be checked. If 0,
  14232. this is a first channel, and the zero'th channel will be
  14233. checked.
  14234. Return Value:
  14235. non-zero - the channel supports keep alives
  14236. 0 - the channel doesn't support keep alives
  14237. --*/
  14238. {
  14239. HTTP2ClientOutChannel *OutChannel;
  14240. BOOL IsKeepAlive;
  14241. HTTP2ChannelPointer *OutChannelPtr;
  14242. if (IsReplacementChannel)
  14243. OutChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  14244. else
  14245. OutChannelPtr = &OutChannels[0];
  14246. OutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  14247. // nobody can abort the connection here
  14248. ASSERT (OutChannel != NULL);
  14249. IsKeepAlive = OutChannel->IsKeepAlive();
  14250. OutChannelPtr->UnlockChannelPointer();
  14251. return IsKeepAlive;
  14252. }
  14253. ULONG HTTP2ClientVirtualConnection::GetInChannelChosenScheme (
  14254. IN BOOL IsReplacementChannel
  14255. )
  14256. /*++
  14257. Routine Description:
  14258. Gets the chosen scheme for the an in channel
  14259. Which channel depends on the arguments - see below.
  14260. Arguments:
  14261. IsReplacementInChannel - if non-zero, this is a replacement
  14262. channel and the non-default channel will be checked. If 0,
  14263. this is a first channel, and the zero'th channel will be
  14264. checked.
  14265. Return Value:
  14266. Chosen scheme
  14267. --*/
  14268. {
  14269. HTTP2ClientInChannel *InChannel;
  14270. ULONG ChosenScheme;
  14271. HTTP2ChannelPointer *InChannelPtr;
  14272. if (IsReplacementChannel)
  14273. InChannelPtr = &InChannels[GetNonDefaultInChannelSelector()];
  14274. else
  14275. InChannelPtr = &InChannels[0];
  14276. InChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  14277. // nobody can abort the connection here
  14278. ASSERT (InChannel != NULL);
  14279. ChosenScheme = InChannel->GetChosenAuthScheme();
  14280. InChannelPtr->UnlockChannelPointer();
  14281. return ChosenScheme;
  14282. }
  14283. ULONG HTTP2ClientVirtualConnection::GetOutChannelChosenScheme (
  14284. IN BOOL IsReplacementChannel
  14285. )
  14286. /*++
  14287. Routine Description:
  14288. Gets the chosen scheme for an out channel
  14289. Which channel depends on the arguments - see below.
  14290. Arguments:
  14291. IsReplacementInChannel - if non-zero, this is a replacement
  14292. channel and the non-default channel will be checked. If 0,
  14293. this is a first channel, and the zero'th channel will be
  14294. checked.
  14295. Return Value:
  14296. Chosen scheme
  14297. --*/
  14298. {
  14299. HTTP2ClientOutChannel *OutChannel;
  14300. ULONG ChosenScheme;
  14301. HTTP2ChannelPointer *OutChannelPtr;
  14302. if (IsReplacementChannel)
  14303. OutChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  14304. else
  14305. OutChannelPtr = &OutChannels[0];
  14306. OutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  14307. // nobody can abort the connection here
  14308. ASSERT (OutChannel != NULL);
  14309. ChosenScheme = OutChannel->GetChosenAuthScheme();
  14310. OutChannelPtr->UnlockChannelPointer();
  14311. return ChosenScheme;
  14312. }
  14313. BOOL HTTP2ClientVirtualConnection::IsInChannelPositiveWithWait (
  14314. void
  14315. )
  14316. /*++
  14317. Routine Description:
  14318. Checks if the in channel has come in with positive result. If
  14319. not, it waits a bit and tries again. If not again, return FALSE.
  14320. Arguments:
  14321. Return Value:
  14322. non-zero if the in channel came in positive.
  14323. 0 otherwise.
  14324. --*/
  14325. {
  14326. if ((InOpenStatus == RPC_S_OK)
  14327. || (InOpenStatus == RPC_P_AUTH_NEEDED))
  14328. return TRUE;
  14329. Sleep(100);
  14330. return ((InOpenStatus == RPC_S_OK)
  14331. || (InOpenStatus == RPC_P_AUTH_NEEDED));
  14332. }
  14333. /*********************************************************************
  14334. Switching Layer
  14335. *********************************************************************/
  14336. RPC_STATUS
  14337. RPC_ENTRY
  14338. HTTP_SyncRecv(
  14339. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14340. OUT BUFFER *pBuffer,
  14341. OUT PUINT pBufferLength,
  14342. IN DWORD dwTimeout
  14343. )
  14344. /*++
  14345. Routine Description:
  14346. Perform a sync recv on an HTTP connection. Part of the HTTP switching
  14347. layer between old mode and new mode.
  14348. Arguments:
  14349. ThisConnection - transport connection
  14350. Buffer - if successful, points to a buffer containing the next PDU.
  14351. BufferLength - if successful, contains the length of the message.
  14352. Timeout - the amount of time to wait for the receive. If -1, we wait
  14353. infinitely.
  14354. Return Value:
  14355. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  14356. --*/
  14357. {
  14358. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14359. HTTP2VirtualConnection *VirtualConnection;
  14360. RPC_STATUS RpcStatus;
  14361. if (BaseObject->id == HTTP)
  14362. {
  14363. return WS_SyncRecv(ThisConnection,
  14364. pBuffer,
  14365. pBufferLength,
  14366. dwTimeout
  14367. );
  14368. }
  14369. else
  14370. {
  14371. ASSERT(BaseObject->id == HTTPv2);
  14372. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14373. RpcStatus = VirtualConnection->SyncRecv((BYTE **)pBuffer,
  14374. (ULONG *)pBufferLength,
  14375. dwTimeout);
  14376. VALIDATE(RpcStatus)
  14377. {
  14378. RPC_S_OK,
  14379. RPC_S_OUT_OF_MEMORY,
  14380. RPC_S_OUT_OF_RESOURCES,
  14381. RPC_P_RECEIVE_FAILED,
  14382. RPC_S_CALL_CANCELLED,
  14383. RPC_P_SEND_FAILED,
  14384. RPC_P_CONNECTION_SHUTDOWN,
  14385. RPC_P_TIMEOUT
  14386. } END_VALIDATE;
  14387. return RpcStatus;
  14388. }
  14389. }
  14390. RPC_STATUS
  14391. RPC_ENTRY
  14392. HTTP_Abort (
  14393. IN RPC_TRANSPORT_CONNECTION Connection
  14394. )
  14395. /*++
  14396. Routine Description:
  14397. Aborts an HTTP connection. Part of the HTTP switching
  14398. layer between old mode and new mode.
  14399. Arguments:
  14400. Connection - transport connection
  14401. Return Value:
  14402. RPC_S_OK
  14403. --*/
  14404. {
  14405. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) Connection;
  14406. HTTP2VirtualConnection *VirtualConnection;
  14407. if (BaseObject->id == HTTP)
  14408. {
  14409. return WS_Abort(Connection);
  14410. }
  14411. else
  14412. {
  14413. ASSERT(BaseObject->id == HTTPv2);
  14414. VirtualConnection = (HTTP2VirtualConnection *)Connection;
  14415. if ((VirtualConnection->type & TYPE_MASK) == CLIENT)
  14416. {
  14417. ((HTTP2ClientVirtualConnection *)VirtualConnection)->HTTP2ClientVirtualConnection::Abort();
  14418. }
  14419. else
  14420. {
  14421. ASSERT((VirtualConnection->type & TYPE_MASK) == SERVER);
  14422. ((HTTP2ServerVirtualConnection *)VirtualConnection)->HTTP2ServerVirtualConnection::Abort();
  14423. }
  14424. return RPC_S_OK;
  14425. }
  14426. }
  14427. RPC_STATUS
  14428. RPC_ENTRY
  14429. HTTP_Close (
  14430. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14431. IN BOOL fDontFlush
  14432. )
  14433. /*++
  14434. Routine Description:
  14435. Aborts an HTTP connection. Part of the HTTP switching
  14436. layer between old mode and new mode.
  14437. Arguments:
  14438. ThisConnection - transport connection
  14439. DontFlush - non-zero if all buffers need to be flushed
  14440. before closing the connection. Zero otherwise.
  14441. Return Value:
  14442. RPC_S_OK
  14443. --*/
  14444. {
  14445. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14446. HTTP2VirtualConnection *VirtualConnection;
  14447. if (BaseObject->id == HTTP)
  14448. {
  14449. return WS_Close(ThisConnection,
  14450. fDontFlush
  14451. );
  14452. }
  14453. else if (BaseObject->id == INVALID_PROTOCOL_ID)
  14454. {
  14455. // object was never completely initialized - just return
  14456. return RPC_S_OK;
  14457. }
  14458. else
  14459. {
  14460. ASSERT(BaseObject->id == HTTPv2);
  14461. // the object may have been destroyed by now - cannot use
  14462. // virtual functions. Determine statically the type
  14463. // and call the function to cleanup (it knows how to
  14464. // deal with destroyed objects)
  14465. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14466. if ((VirtualConnection->type & TYPE_MASK) == CLIENT)
  14467. {
  14468. ((HTTP2ClientVirtualConnection *)VirtualConnection)->HTTP2ClientVirtualConnection::Close(fDontFlush);
  14469. }
  14470. else
  14471. {
  14472. ASSERT((VirtualConnection->type & TYPE_MASK) == SERVER);
  14473. ((HTTP2ServerVirtualConnection *)VirtualConnection)->HTTP2ServerVirtualConnection::Close(fDontFlush);
  14474. }
  14475. return RPC_S_OK;
  14476. }
  14477. }
  14478. RPC_STATUS
  14479. RPC_ENTRY
  14480. HTTP_Send(
  14481. RPC_TRANSPORT_CONNECTION ThisConnection,
  14482. UINT Length,
  14483. BUFFER Buffer,
  14484. PVOID SendContext
  14485. )
  14486. /*++
  14487. Routine Description:
  14488. Does a send on an HTTP connection. Part of the HTTP switching
  14489. layer between old mode and new mode.
  14490. Arguments:
  14491. ThisConnection - The connection to send the data on.
  14492. Length - The length of the data to send.
  14493. Buffer - The data to send.
  14494. SendContext - A buffer to use as the HTTP2SendContext for
  14495. this operation.
  14496. Return Value:
  14497. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  14498. --*/
  14499. {
  14500. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14501. HTTP2VirtualConnection *VirtualConnection;
  14502. if (BaseObject->id == HTTP)
  14503. {
  14504. return CO_Send(ThisConnection,
  14505. Length,
  14506. Buffer,
  14507. SendContext
  14508. );
  14509. }
  14510. else
  14511. {
  14512. ASSERT(BaseObject->id == HTTPv2);
  14513. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14514. return VirtualConnection->Send(Length,
  14515. Buffer,
  14516. SendContext
  14517. );
  14518. }
  14519. }
  14520. RPC_STATUS
  14521. RPC_ENTRY
  14522. HTTP_Recv(
  14523. RPC_TRANSPORT_CONNECTION ThisConnection
  14524. )
  14525. /*++
  14526. Routine Description:
  14527. Does a receive on an HTTP connection. Part of the HTTP switching
  14528. layer between old mode and new mode.
  14529. Arguments:
  14530. ThisConnection - A connection without a read pending on it.
  14531. Return Value:
  14532. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  14533. --*/
  14534. {
  14535. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14536. HTTP2VirtualConnection *VirtualConnection;
  14537. if (BaseObject->id == HTTP)
  14538. {
  14539. return CO_Recv(ThisConnection);
  14540. }
  14541. else
  14542. {
  14543. ASSERT(BaseObject->id == HTTPv2);
  14544. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14545. return VirtualConnection->Receive();
  14546. }
  14547. }
  14548. RPC_STATUS
  14549. RPC_ENTRY
  14550. HTTP_SyncSend(
  14551. IN RPC_TRANSPORT_CONNECTION Connection,
  14552. IN UINT BufferLength,
  14553. IN BUFFER Buffer,
  14554. IN BOOL fDisableShutdownCheck,
  14555. IN BOOL fDisableCancelCheck,
  14556. ULONG Timeout
  14557. )
  14558. /*++
  14559. Routine Description:
  14560. Does a sync send on an HTTP connection. Part of the HTTP switching
  14561. layer between old mode and new mode.
  14562. Arguments:
  14563. Connection - The connection to send on.
  14564. BufferLength - The size of the buffer.
  14565. Buffer - The data to sent.
  14566. fDisableShutdownCheck - Normally FALSE, when true this disables
  14567. the transport check for async shutdown PDUs.
  14568. fDisableCancelCheck - runtime indicates no cancel
  14569. will be attempted on this send. Can be used
  14570. as optimization hint by the transport
  14571. Timeout - send timeout (call timeout)
  14572. Return Value:
  14573. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  14574. --*/
  14575. {
  14576. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) Connection;
  14577. HTTP2VirtualConnection *VirtualConnection;
  14578. RPC_STATUS RpcStatus;
  14579. if (BaseObject->id == HTTP)
  14580. {
  14581. RpcStatus = WS_SyncSend(Connection,
  14582. BufferLength,
  14583. Buffer,
  14584. fDisableShutdownCheck,
  14585. fDisableCancelCheck,
  14586. Timeout
  14587. );
  14588. }
  14589. else
  14590. {
  14591. ASSERT(BaseObject->id == HTTPv2);
  14592. VirtualConnection = (HTTP2VirtualConnection *)Connection;
  14593. RpcStatus = VirtualConnection->SyncSend(BufferLength,
  14594. Buffer,
  14595. fDisableShutdownCheck,
  14596. fDisableCancelCheck,
  14597. Timeout
  14598. );
  14599. }
  14600. VALIDATE(RpcStatus)
  14601. {
  14602. RPC_S_OK,
  14603. RPC_S_OUT_OF_MEMORY,
  14604. RPC_S_OUT_OF_RESOURCES,
  14605. RPC_P_RECEIVE_FAILED,
  14606. RPC_S_CALL_CANCELLED,
  14607. RPC_P_SEND_FAILED,
  14608. RPC_P_CONNECTION_SHUTDOWN,
  14609. RPC_P_TIMEOUT
  14610. } END_VALIDATE;
  14611. return RpcStatus;
  14612. }
  14613. RPC_STATUS
  14614. RPC_ENTRY
  14615. HTTP_TurnOnOffKeepAlives (
  14616. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14617. IN BOOL TurnOn,
  14618. IN BOOL bProtectIO,
  14619. IN KEEPALIVE_TIMEOUT_UNITS Units,
  14620. IN OUT KEEPALIVE_TIMEOUT KATime,
  14621. IN ULONG KAInterval OPTIONAL
  14622. )
  14623. /*++
  14624. Routine Description:
  14625. Turns on keep alives for an HTTP connection. Part of the HTTP switching
  14626. layer between old mode and new mode.
  14627. Arguments:
  14628. ThisConnection - The connection to turn keep alives on on.
  14629. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  14630. are turned off.
  14631. bProtectIO - non-zero if IO needs to be protected against async close
  14632. of the connection.
  14633. Units - in what units is KATime
  14634. KATime - how much to wait before turning on keep alives
  14635. KAInterval - the interval between keep alives
  14636. Return Value:
  14637. RPC_S_OK or RPC_S_* / Win32 errors on failure
  14638. Note:
  14639. If we use it on the server, we must protect
  14640. the connection against async aborts.
  14641. --*/
  14642. {
  14643. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14644. HTTP2VirtualConnection *VirtualConnection;
  14645. if (BaseObject->id == HTTP)
  14646. {
  14647. return WS_TurnOnOffKeepAlives(ThisConnection,
  14648. TurnOn,
  14649. bProtectIO,
  14650. Units,
  14651. KATime,
  14652. KAInterval
  14653. );
  14654. }
  14655. else
  14656. {
  14657. ASSERT(BaseObject->id == HTTPv2);
  14658. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14659. return VirtualConnection->TurnOnOffKeepAlives(TurnOn,
  14660. bProtectIO,
  14661. FALSE, // IsFromUpcall
  14662. Units,
  14663. KATime,
  14664. KAInterval
  14665. );
  14666. }
  14667. }
  14668. RPC_STATUS
  14669. RPC_ENTRY
  14670. HTTP_QueryClientAddress (
  14671. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14672. OUT RPC_CHAR **pNetworkAddress
  14673. )
  14674. /*++
  14675. Routine Description:
  14676. Returns the IP address of the client on a connection as a string.
  14677. Arguments:
  14678. NetworkAddress - Will contain string on success.
  14679. Return Value:
  14680. RPC_S_OK or other RPC_S_* errors for error
  14681. --*/
  14682. {
  14683. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14684. HTTP2VirtualConnection *VirtualConnection;
  14685. if (BaseObject->id == HTTP)
  14686. {
  14687. return TCP_QueryClientAddress(ThisConnection,
  14688. pNetworkAddress
  14689. );
  14690. }
  14691. else
  14692. {
  14693. ASSERT(BaseObject->id == HTTPv2);
  14694. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14695. return VirtualConnection->QueryClientAddress(pNetworkAddress);
  14696. }
  14697. }
  14698. RPC_STATUS
  14699. RPC_ENTRY
  14700. HTTP_QueryLocalAddress (
  14701. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14702. IN OUT void *Buffer,
  14703. IN OUT unsigned long *BufferSize,
  14704. OUT unsigned long *AddressFormat
  14705. )
  14706. /*++
  14707. Routine Description:
  14708. Returns the local IP address of a connection.
  14709. Arguments:
  14710. Buffer - The buffer that will receive the output address
  14711. BufferSize - the size of the supplied Buffer on input. On output the
  14712. number of bytes written to the buffer. If the buffer is too small
  14713. to receive all the output data, ERROR_MORE_DATA is returned,
  14714. nothing is written to the buffer, and BufferSize is set to
  14715. the size of the buffer needed to return all the data.
  14716. AddressFormat - a constant indicating the format of the returned address.
  14717. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  14718. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  14719. Return Value:
  14720. RPC_S_OK or other RPC_S_* errors for error
  14721. --*/
  14722. {
  14723. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14724. HTTP2VirtualConnection *VirtualConnection;
  14725. if (BaseObject->id == HTTP)
  14726. {
  14727. return TCP_QueryLocalAddress(ThisConnection,
  14728. Buffer,
  14729. BufferSize,
  14730. AddressFormat
  14731. );
  14732. }
  14733. else
  14734. {
  14735. ASSERT(BaseObject->id == HTTPv2);
  14736. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14737. return VirtualConnection->QueryLocalAddress(Buffer,
  14738. BufferSize,
  14739. AddressFormat
  14740. );
  14741. }
  14742. }
  14743. RPC_STATUS
  14744. RPC_ENTRY
  14745. HTTP_QueryClientId(
  14746. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14747. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  14748. )
  14749. /*++
  14750. Routine Description:
  14751. For secure protocols (which TCP/IP is not) this is supposed to
  14752. give an ID which will be shared by all clients from the same
  14753. process. This prevents one user from grabbing another users
  14754. association group and using their context handles.
  14755. Since TCP/IP is not secure we return the IP address of the
  14756. client machine. This limits the attacks to other processes
  14757. running on the client machine which is better than nothing.
  14758. Arguments:
  14759. ClientProcess - Transport identification of the "client".
  14760. Return Value:
  14761. RPC_S_OK or other RPC_S_* errors for error
  14762. --*/
  14763. {
  14764. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14765. HTTP2VirtualConnection *VirtualConnection;
  14766. if (BaseObject->id == HTTP)
  14767. {
  14768. return TCP_QueryClientId(ThisConnection,
  14769. ClientProcess
  14770. );
  14771. }
  14772. else
  14773. {
  14774. ASSERT(BaseObject->id == HTTPv2);
  14775. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14776. return VirtualConnection->QueryClientId(ClientProcess);
  14777. }
  14778. }
  14779. /*********************************************************************
  14780. HTTP Transport Interface
  14781. *********************************************************************/
  14782. const int HTTPClientConnectionSize = max(sizeof(WS_CLIENT_CONNECTION), sizeof(WS_SAN_CLIENT_CONNECTION));
  14783. const int HTTP2ClientConnectionSize = sizeof(HTTP2ClientVirtualConnection);
  14784. const int HTTPServerConnectionSize = max(sizeof(WS_CONNECTION), sizeof(WS_SAN_CONNECTION));
  14785. const int HTTP2ServerConnectionSize = max(sizeof(HTTP2ServerVirtualConnection), sizeof(WS_HTTP2_INITIAL_CONNECTION));
  14786. const RPC_CONNECTION_TRANSPORT
  14787. HTTP_TransportInterface =
  14788. {
  14789. RPC_TRANSPORT_INTERFACE_VERSION,
  14790. HTTP_TOWER_ID,
  14791. HTTP_ADDRESS_ID,
  14792. RPC_STRING_LITERAL("ncacn_http"),
  14793. "593",
  14794. COMMON_ProcessCalls,
  14795. COMMON_StartPnpNotifications,
  14796. COMMON_ListenForPNPNotifications,
  14797. COMMON_TowerConstruct,
  14798. COMMON_TowerExplode,
  14799. COMMON_PostRuntimeEvent,
  14800. FALSE,
  14801. sizeof(WS_ADDRESS),
  14802. max(HTTPClientConnectionSize, HTTP2ClientConnectionSize),
  14803. max(HTTPServerConnectionSize, HTTP2ServerConnectionSize),
  14804. sizeof(HTTP2SendContext),
  14805. sizeof(HTTPResolverHint),
  14806. HTTP_MAX_SEND,
  14807. HTTP_Initialize,
  14808. 0, // InitComplete,
  14809. HTTP_Open,
  14810. 0, // No SendRecv on winsock
  14811. HTTP_SyncRecv,
  14812. HTTP_Abort,
  14813. HTTP_Close,
  14814. HTTP_Send,
  14815. HTTP_Recv,
  14816. HTTP_SyncSend,
  14817. HTTP_TurnOnOffKeepAlives,
  14818. HTTP_ServerListen,
  14819. WS_ServerAbortListen,
  14820. COMMON_ServerCompleteListen,
  14821. HTTP_QueryClientAddress,
  14822. HTTP_QueryLocalAddress,
  14823. HTTP_QueryClientId,
  14824. 0, // Impersonate
  14825. 0, // Revert
  14826. HTTP_FreeResolverHint,
  14827. HTTP_CopyResolverHint,
  14828. HTTP_CompareResolverHint,
  14829. HTTP_SetLastBufferToFree
  14830. };
  14831. /*********************************************************************
  14832. HTTP2ProxyServerSideChannel
  14833. *********************************************************************/
  14834. RPC_STATUS HTTP2ProxyServerSideChannel::InitializeRawConnection (
  14835. IN RPC_CHAR *ServerName,
  14836. IN USHORT ServerPort,
  14837. IN ULONG ConnectionTimeout,
  14838. IN I_RpcProxyIsValidMachineFn IsValidMachineFn
  14839. )
  14840. /*++
  14841. Routine Description:
  14842. Initializes a raw connection.
  14843. Arguments:
  14844. ServerName - the server to connect to.
  14845. ServerPort - which port on that server to use
  14846. ConnectionTimeout - the connection timeout to use.
  14847. IsValidMachineFn - a callback function to verify if the
  14848. target machine/port are not blocked
  14849. Return Value:
  14850. RPC_S_OK or RPC_S_* for error
  14851. --*/
  14852. {
  14853. RPC_STATUS RpcStatus;
  14854. HTTPResolverHint DummyHint;
  14855. RpcStatus = TCPOrHTTP_Open(RawConnection,
  14856. ServerName,
  14857. ServerPort,
  14858. ConnectionTimeout,
  14859. 0, // SendBufferSize
  14860. 0, // RecvBufferSize
  14861. &DummyHint,
  14862. FALSE, // HintWasInitialized
  14863. 10 * 60 * 60, // 10 minutes
  14864. TRUE, // fHTTP2Open
  14865. IsValidMachineFn
  14866. );
  14867. return RpcStatus;
  14868. }
  14869. /*********************************************************************
  14870. HTTP2TimeoutTargetConnection
  14871. *********************************************************************/
  14872. RPC_STATUS HTTP2TimeoutTargetConnection::SetTimeout (
  14873. IN ULONG Timeout,
  14874. IN ULONG TimerIndex
  14875. )
  14876. /*++
  14877. Routine Description:
  14878. Called to setup a one time timer. Caller must make
  14879. sure this function is synchronized with CancelTimeout and
  14880. must make sure we don't schedule a timer behind an aborting
  14881. thread (i.e. a timer fires after the object goes away).
  14882. Arguments:
  14883. Timeout - interval before the timer fires
  14884. TimerIndex - which timer do we refer to.
  14885. Return Value:
  14886. RPC_S_OK or RPC_S_* error
  14887. --*/
  14888. {
  14889. BOOL Result;
  14890. VerifyValidTimerIndex(TimerIndex);
  14891. ASSERT(TimerHandle[TimerIndex] == NULL);
  14892. Result = CreateTimerQueueTimer(&TimerHandle[TimerIndex],
  14893. NULL,
  14894. HTTP2TimeoutTimerCallback,
  14895. this,
  14896. Timeout, // time to first fire
  14897. 0, // periodic interval
  14898. WT_EXECUTELONGFUNCTION
  14899. );
  14900. if (Result == FALSE)
  14901. return RPC_S_OUT_OF_MEMORY;
  14902. return RPC_S_OK;
  14903. }
  14904. void HTTP2TimeoutTargetConnection::CancelTimeout (
  14905. IN ULONG TimerIndex
  14906. )
  14907. /*++
  14908. Routine Description:
  14909. Called to cancel a timer. The function will not return until
  14910. the timer callbacks have been drained. Caller must ensure
  14911. that this method is synchronized with SetTimeout
  14912. Arguments:
  14913. TimerIndex - which timer do we refer to.
  14914. Return Value:
  14915. --*/
  14916. {
  14917. HANDLE LocalTimerHandle;
  14918. BOOL Result;
  14919. VerifyValidTimerIndex(TimerIndex);
  14920. LocalTimerHandle = InterlockedExchangePointer(&TimerHandle[TimerIndex], NULL);
  14921. // if the timer already fired there is nothing to do here.
  14922. if (LocalTimerHandle == NULL)
  14923. return;
  14924. Result = DeleteTimerQueueTimer(NULL,
  14925. LocalTimerHandle,
  14926. INVALID_HANDLE_VALUE // tell the timer function to wait for all callbacks
  14927. // to complete before returning
  14928. );
  14929. // this cannot fail unless we give it invalid parameters
  14930. ASSERT(Result);
  14931. }
  14932. /*********************************************************************
  14933. HTTP2ProxyVirtualConnection
  14934. *********************************************************************/
  14935. RPC_STATUS HTTP2ProxyVirtualConnection::SendComplete (
  14936. IN RPC_STATUS EventStatus,
  14937. IN OUT HTTP2SendContext *SendContext,
  14938. IN int ChannelId
  14939. )
  14940. /*++
  14941. Routine Description:
  14942. Called by lower layers to indicate send complete.
  14943. Arguments:
  14944. EventStatus - status of the operation
  14945. SendContext - the context for the send complete
  14946. ChannelId - which channel completed the operation
  14947. Return Value:
  14948. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  14949. be hidden from the runtime.
  14950. RPC_S_OK if the packet was processed successfully.
  14951. RPC_S_* error if there was an error while processing the
  14952. packet.
  14953. --*/
  14954. {
  14955. HTTP2ChannelPointer *ChannelPtr;
  14956. HTTP2InProxyInChannel *InProxyInChannel;
  14957. HTTP2OutProxyInChannel *OutProxyInChannel;
  14958. BOOL LocalIsInProxy;
  14959. BOOL IssueAck;
  14960. ULONG BytesReceivedForAck;
  14961. ULONG WindowForAck;
  14962. BOOL UnlockPointer;
  14963. VerifyValidChannelId(ChannelId);
  14964. if ((EventStatus == RPC_S_OK)
  14965. && (SendContext->TrafficType == http2ttData))
  14966. {
  14967. ChannelPtr = MapSendContextUserDataToChannelPtr(SendContext->UserData);
  14968. if (ChannelPtr)
  14969. {
  14970. UnlockPointer = FALSE;
  14971. IssueAck = FALSE;
  14972. LocalIsInProxy = IsInProxy();
  14973. if (LocalIsInProxy)
  14974. {
  14975. InProxyInChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  14976. if (InProxyInChannel)
  14977. {
  14978. UnlockPointer = TRUE;
  14979. InProxyInChannel->BytesConsumedNotification (SendContext->maxWriteBuffer,
  14980. FALSE, // OwnsMutex
  14981. &IssueAck,
  14982. &BytesReceivedForAck,
  14983. &WindowForAck
  14984. );
  14985. }
  14986. }
  14987. else
  14988. {
  14989. OutProxyInChannel = (HTTP2OutProxyInChannel *)ChannelPtr->LockChannelPointer();
  14990. if (OutProxyInChannel)
  14991. {
  14992. UnlockPointer = TRUE;
  14993. OutProxyInChannel->BytesConsumedNotification (SendContext->maxWriteBuffer,
  14994. FALSE, // OwnsMutex
  14995. &IssueAck,
  14996. &BytesReceivedForAck,
  14997. &WindowForAck
  14998. );
  14999. }
  15000. }
  15001. if (IssueAck)
  15002. {
  15003. // we need to issue a flow control ack to the peer. InProxy uses
  15004. // forwarding, out proxy sends ack directly
  15005. if (LocalIsInProxy)
  15006. {
  15007. EventStatus = InProxyInChannel->ForwardFlowControlAck(
  15008. BytesReceivedForAck,
  15009. WindowForAck
  15010. );
  15011. }
  15012. else
  15013. {
  15014. EventStatus = OutProxyInChannel->ForwardFlowControlAck(
  15015. BytesReceivedForAck,
  15016. WindowForAck
  15017. );
  15018. }
  15019. #if DBG_ERROR
  15020. DbgPrint("%s proxy issuing flow control ack: %d, %d\n",
  15021. LocalIsInProxy ? "IN" : "OUT",
  15022. BytesReceivedForAck, WindowForAck);
  15023. #endif
  15024. }
  15025. if (UnlockPointer)
  15026. ChannelPtr->UnlockChannelPointer();
  15027. }
  15028. else
  15029. {
  15030. #if DBG
  15031. DbgPrint("RPCRT4: %d: Channel for User Data %d on connection %p not found\n",
  15032. GetCurrentProcessId(),
  15033. SendContext->UserData,
  15034. this
  15035. );
  15036. #endif
  15037. }
  15038. }
  15039. // successful sends are no-op. Failed sends cause abort. Just
  15040. // turn around the operation status after freeing the packet
  15041. FreeSendContextAndPossiblyData(SendContext);
  15042. // ok to return any error code. See Rule 12
  15043. return EventStatus;
  15044. }
  15045. void HTTP2ProxyVirtualConnection::Abort (
  15046. void
  15047. )
  15048. /*++
  15049. Routine Description:
  15050. Aborts an HTTP connection and disconnects the channels.
  15051. Must only come from neutral context.
  15052. Arguments:
  15053. Return Value:
  15054. --*/
  15055. {
  15056. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PROXY_VC, 0);
  15057. // abort the channels themselves
  15058. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  15059. // we got to the destructive phase of the abort
  15060. // guard against double aborts
  15061. if (Aborted.Increment() > 1)
  15062. return;
  15063. DisconnectChannels(FALSE, 0);
  15064. }
  15065. void HTTP2ProxyVirtualConnection::DisconnectChannels (
  15066. IN BOOL ExemptChannel,
  15067. IN int ExemptChannelId
  15068. )
  15069. /*++
  15070. Routine Description:
  15071. Disconnects all channels. Must be called from runtime
  15072. or neutral context. Cannot be called from upcall or
  15073. submit context unless an exempt channel is given
  15074. Note that call must synchronize to ensure we're the only
  15075. thread doing the disconnect
  15076. Arguments:
  15077. ExemptChannel - non-zero if ExemptChannelId contains a
  15078. valid exempt channel id. FALSE otherwise.
  15079. ExemptChannelId - if ExemptChannel is non-zero, this argument
  15080. is the id of a channel that will be disconnected, but not
  15081. synchronized with up calls.
  15082. If ExampleChannel is FALSE, this argument is undefined
  15083. Return Value:
  15084. --*/
  15085. {
  15086. while (RundownBlock.GetInteger() > 0)
  15087. {
  15088. Sleep(2);
  15089. }
  15090. RemoveConnectionFromCookieCollection();
  15091. HTTP2VirtualConnection::DisconnectChannels(ExemptChannel,
  15092. ExemptChannelId
  15093. );
  15094. // cancel the timeouts after we have disconnected the channels.
  15095. // Since all timeouts are setup within upcalls
  15096. CancelAllTimeouts();
  15097. }
  15098. RPC_STATUS HTTP2ProxyVirtualConnection::AddConnectionToCookieCollection (
  15099. void
  15100. )
  15101. /*++
  15102. Routine Description:
  15103. Adds this virtual connection to the cookie collection
  15104. Arguments:
  15105. Return Value:
  15106. --*/
  15107. {
  15108. CookieCollection *ProxyCookieCollection;
  15109. HTTP2VirtualConnection *ExistingConnection;
  15110. if (IsInProxy())
  15111. ProxyCookieCollection = GetInProxyCookieCollection();
  15112. else
  15113. ProxyCookieCollection = GetOutProxyCookieCollection();
  15114. ProxyConnectionCookie = new HTTP2ServerCookie(EmbeddedConnectionCookie);
  15115. if (ProxyConnectionCookie == NULL)
  15116. return RPC_S_OUT_OF_MEMORY;
  15117. ProxyConnectionCookie->SetConnection(this);
  15118. IsConnectionInCollection = TRUE;
  15119. ProxyCookieCollection->LockCollection();
  15120. ExistingConnection = ProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  15121. if (ExistingConnection == NULL)
  15122. ProxyCookieCollection->AddElement(ProxyConnectionCookie);
  15123. ProxyCookieCollection->UnlockCollection();
  15124. if (ExistingConnection)
  15125. return RPC_S_PROTOCOL_ERROR;
  15126. else
  15127. return RPC_S_OK;
  15128. }
  15129. void HTTP2ProxyVirtualConnection::RemoveConnectionFromCookieCollection (
  15130. void
  15131. )
  15132. /*++
  15133. Routine Description:
  15134. Removes this virtual connection from the cookie collection
  15135. Arguments:
  15136. Return Value:
  15137. Note:
  15138. This function must be called exactly once and is not thread safe.
  15139. --*/
  15140. {
  15141. CookieCollection *ProxyCookieCollection;
  15142. if (IsConnectionInCollection)
  15143. {
  15144. ASSERT(ProxyConnectionCookie);
  15145. if (ProxyConnectionCookie->RemoveRefCount())
  15146. {
  15147. if (IsInProxy())
  15148. ProxyCookieCollection = GetInProxyCookieCollection();
  15149. else
  15150. ProxyCookieCollection = GetOutProxyCookieCollection();
  15151. ProxyCookieCollection->LockCollection();
  15152. ProxyCookieCollection->RemoveElement(ProxyConnectionCookie);
  15153. ProxyCookieCollection->UnlockCollection();
  15154. delete ProxyConnectionCookie;
  15155. }
  15156. else
  15157. {
  15158. // the only we we can have a non-zero refcount is if the same
  15159. // machine fakes a web farm.
  15160. ASSERT(ActAsSeparateMachinesOnWebFarm);
  15161. }
  15162. }
  15163. }
  15164. void HTTP2ProxyVirtualConnection::TimeoutExpired (
  15165. void
  15166. )
  15167. /*++
  15168. Routine Description:
  15169. A timeout expired before we cancelled the timer. Abort the connection.
  15170. Arguments:
  15171. Return Value:
  15172. --*/
  15173. {
  15174. BOOL Result;
  15175. TimerExpiredNotify();
  15176. Result = AbortAndDestroy(FALSE, // IsFromChannel
  15177. 0, // CallingChannelId
  15178. RPC_P_TIMEOUT
  15179. );
  15180. // if somebody is already destroying it, just return
  15181. if (Result == FALSE)
  15182. return;
  15183. // now 'this' is a pointer disconnected from everybody
  15184. // that we can destroy at our leisure
  15185. delete this;
  15186. }
  15187. /*********************************************************************
  15188. HTTP2InProxyInChannel
  15189. *********************************************************************/
  15190. RPC_STATUS HTTP2InProxyInChannel::ForwardFlowControlAck (
  15191. IN ULONG BytesReceivedForAck,
  15192. IN ULONG WindowForAck
  15193. )
  15194. /*++
  15195. Routine Description:
  15196. Forwards a flow control ack to the client through the server
  15197. Arguments:
  15198. BytesReceivedForAck - the bytes received when the ACK was issued
  15199. WindowForAck - the free window when the ACK was issued.
  15200. Return Value:
  15201. RPC_S_OK or RPC_S_*
  15202. --*/
  15203. {
  15204. return ForwardFlowControlAckOnDefaultChannel(FALSE, // IsInChannel
  15205. fdClient,
  15206. BytesReceivedForAck,
  15207. WindowForAck
  15208. );
  15209. }
  15210. /*********************************************************************
  15211. HTTP2InProxyOutChannel
  15212. *********************************************************************/
  15213. RPC_STATUS HTTP2InProxyOutChannel::LastPacketSentNotification (
  15214. IN HTTP2SendContext *LastSendContext
  15215. )
  15216. /*++
  15217. Routine Description:
  15218. When a lower channel wants to notify the top
  15219. channel that the last packet has been sent,
  15220. they call this function. Must be called from
  15221. an upcall/neutral context. Only flow control
  15222. senders support last packet notifications
  15223. Arguments:
  15224. LastSendContext - the context for the last send
  15225. Return Value:
  15226. The value to return to the bottom channel
  15227. --*/
  15228. {
  15229. // just return ok to caller. When the server aborts the connection,
  15230. // we will abort too.
  15231. return RPC_S_OK;
  15232. }
  15233. RPC_STATUS HTTP2InProxyOutChannel::SetRawConnectionKeepAlive (
  15234. IN ULONG KeepAliveInterval // in milliseconds
  15235. )
  15236. /*++
  15237. Routine Description:
  15238. Sets the raw connection keep alive. On abort connections
  15239. failures are ignored.
  15240. Arguments:
  15241. KeepAliveInterval - keep alive interval in milliseconds
  15242. Return Value:
  15243. The value to return to the bottom channel
  15244. --*/
  15245. {
  15246. RPC_STATUS RpcStatus;
  15247. WS_HTTP2_CONNECTION *RawConnection;
  15248. KEEPALIVE_TIMEOUT KATimeout;
  15249. RpcStatus = BeginSimpleSubmitAsync();
  15250. if (RpcStatus != RPC_S_OK)
  15251. return RPC_S_OK;
  15252. RawConnection = GetRawConnection();
  15253. KATimeout.Milliseconds = KeepAliveInterval;
  15254. // turn off the old interval
  15255. RpcStatus = WS_TurnOnOffKeepAlives(RawConnection,
  15256. FALSE, // TurnOn
  15257. FALSE, // bProtectIO
  15258. tuMilliseconds,
  15259. KATimeout,
  15260. DefaultClientNoResponseKeepAliveInterval
  15261. );
  15262. // turning off should always succeed
  15263. ASSERT(RpcStatus == RPC_S_OK);
  15264. // turn on the new interval
  15265. // start with the keep alives immediately and proceed until the specified interval
  15266. RpcStatus = WS_TurnOnOffKeepAlives(RawConnection,
  15267. TRUE, // TurnOn
  15268. FALSE, // bProtectIO
  15269. tuMilliseconds,
  15270. KATimeout,
  15271. KeepAliveInterval
  15272. );
  15273. FinishSubmitAsync();
  15274. return RpcStatus;
  15275. }
  15276. /*********************************************************************
  15277. HTTP2InProxyVirtualConnection
  15278. *********************************************************************/
  15279. RPC_STATUS HTTP2InProxyVirtualConnection::InitializeProxyFirstLeg (
  15280. IN USHORT *ServerAddress,
  15281. IN USHORT *ServerPort,
  15282. IN void *ConnectionParameter,
  15283. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface,
  15284. void **IISContext
  15285. )
  15286. /*++
  15287. Routine Description:
  15288. Initialize the proxy (first leg - second leg will happen when we
  15289. receive first RTS packet).
  15290. Arguments:
  15291. ServerAddress - unicode pointer string to the server network address.
  15292. ServerPort - unicode pointer string to the server port
  15293. ConnectionParameter - the extension control block in this case
  15294. ProxyCallbackInterface - a callback interface to the proxy to perform
  15295. various proxy specific functions
  15296. IISContext - on output (success only) it must be initialized to
  15297. the bottom IISChannel for the InProxy.
  15298. Return Value:
  15299. RPC_S_OK or other RPC_S_* errors for error
  15300. --*/
  15301. {
  15302. RPC_STATUS RpcStatus;
  15303. HTTP2InProxyInChannel *NewInChannel;
  15304. int InChannelId;
  15305. int ServerAddressLength; // in characters + terminating 0
  15306. // initialize in channel
  15307. RpcStatus = AllocateAndInitializeInChannel(ConnectionParameter,
  15308. &NewInChannel,
  15309. IISContext
  15310. );
  15311. if (RpcStatus != RPC_S_OK)
  15312. return RpcStatus;
  15313. SetFirstInChannel(NewInChannel);
  15314. this->ProxyCallbackInterface = ProxyCallbackInterface;
  15315. this->ConnectionParameter = ConnectionParameter;
  15316. ServerAddressLength = RpcpStringLength(ServerAddress) + 1;
  15317. ServerName = new RPC_CHAR [ServerAddressLength];
  15318. if (ServerName == NULL)
  15319. {
  15320. Abort();
  15321. return RPC_S_OUT_OF_MEMORY;
  15322. }
  15323. RpcpMemoryCopy(ServerName, ServerAddress, ServerAddressLength * 2);
  15324. RpcStatus = EndpointToPortNumber(ServerPort, this->ServerPort);
  15325. return RpcStatus;
  15326. }
  15327. RPC_STATUS HTTP2InProxyVirtualConnection::StartProxy (
  15328. void
  15329. )
  15330. /*++
  15331. Routine Description:
  15332. Kicks off listening on the proxy
  15333. Arguments:
  15334. Return Value:
  15335. RPC_S_OK or RPC_S_* for error
  15336. --*/
  15337. {
  15338. HTTP2InProxyInChannel *Channel;
  15339. HTTP2ChannelPointer *ChannelPtr;
  15340. RPC_STATUS RpcStatus;
  15341. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svClosed, 1, 0);
  15342. State.State = http2svClosed; // move to closed state expecting the opening RTS packet
  15343. Channel = LockDefaultInChannel(&ChannelPtr);
  15344. ASSERT(Channel != NULL); // we cannot be disconnected now
  15345. RpcStatus = Channel->Receive(http2ttRaw);
  15346. ChannelPtr->UnlockChannelPointer();
  15347. return RpcStatus;
  15348. }
  15349. RPC_STATUS HTTP2InProxyVirtualConnection::InitializeProxySecondLeg (
  15350. void
  15351. )
  15352. /*++
  15353. Routine Description:
  15354. Initialize the proxy (second leg - first leg has happened when we
  15355. received the HTTP establishment header).
  15356. Arguments:
  15357. Return Value:
  15358. RPC_S_OK or other RPC_S_* errors for error
  15359. --*/
  15360. {
  15361. RPC_STATUS RpcStatus;
  15362. HTTP2InProxyOutChannel *NewOutChannel;
  15363. int OutChannelId;
  15364. int ServerAddressLength; // in characters + terminating 0
  15365. char ClientIpAddress[16];
  15366. ULONG ClientIpAddressSize;
  15367. ADDRINFO DnsHint;
  15368. ADDRINFO *AddrInfo;
  15369. int err;
  15370. // initialize out channel
  15371. RpcStatus = AllocateAndInitializeOutChannel(
  15372. &NewOutChannel
  15373. );
  15374. if (RpcStatus != RPC_S_OK)
  15375. {
  15376. Abort();
  15377. return RpcStatus;
  15378. }
  15379. SetFirstOutChannel(NewOutChannel);
  15380. RpcStatus = ProxyCallbackInterface->GetConnectionTimeoutFn(&IISConnectionTimeout);
  15381. if (RpcStatus != RPC_S_OK)
  15382. {
  15383. Abort();
  15384. return RpcStatus;
  15385. }
  15386. // convert it from seconds to milliseconds
  15387. IISConnectionTimeout *= 1000;
  15388. ClientIpAddressSize = sizeof(ClientIpAddress);
  15389. RpcStatus = ProxyCallbackInterface->GetClientAddressFn(
  15390. ConnectionParameter,
  15391. ClientIpAddress,
  15392. &ClientIpAddressSize
  15393. );
  15394. ASSERT(RpcStatus != ERROR_INSUFFICIENT_BUFFER);
  15395. if (RpcStatus != RPC_S_OK)
  15396. {
  15397. Abort();
  15398. return RpcStatus;
  15399. }
  15400. RpcpMemorySet(&DnsHint, 0, sizeof(ADDRINFO));
  15401. DnsHint.ai_flags = AI_NUMERICHOST;
  15402. DnsHint.ai_family = PF_UNSPEC;
  15403. err = getaddrinfo(ClientIpAddress,
  15404. NULL,
  15405. &DnsHint,
  15406. &AddrInfo);
  15407. // make sure IIS doesn't feed us garbage IP address
  15408. if (err != ERROR_SUCCESS)
  15409. {
  15410. ASSERT(GetLastError() == ERROR_OUTOFMEMORY);
  15411. Abort();
  15412. return RPC_S_OUT_OF_MEMORY;
  15413. }
  15414. ASSERT(AddrInfo->ai_family == AF_INET);
  15415. ClientAddress.AddressType = catIPv4;
  15416. RpcpCopyIPv4Address((SOCKADDR_IN *)AddrInfo->ai_addr, (SOCKADDR_IN *)&ClientAddress.u);
  15417. freeaddrinfo(AddrInfo);
  15418. return RpcStatus;
  15419. }
  15420. RPC_STATUS HTTP2InProxyVirtualConnection::ReceiveComplete (
  15421. IN RPC_STATUS EventStatus,
  15422. IN BYTE *Buffer,
  15423. IN UINT BufferLength,
  15424. IN int ChannelId
  15425. )
  15426. /*++
  15427. Routine Description:
  15428. Called by lower layers to indicate receive complete
  15429. Arguments:
  15430. EventStatus - RPC_S_OK for success or RPC_S_* for error
  15431. Buffer - buffer received
  15432. BufferLength - length of buffer received
  15433. ChannelId - which channel completed the operation
  15434. Return Value:
  15435. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  15436. be hidden from the runtime.
  15437. RPC_S_OK if the packet was processed successfully.
  15438. RPC_S_* error if there was an error while processing the
  15439. packet.
  15440. --*/
  15441. {
  15442. RPC_STATUS RpcStatus;
  15443. BOOL BufferFreed = FALSE;
  15444. BOOL MutexCleared;
  15445. HTTP2ChannelPointer *ChannelPtr;
  15446. HTTP2ChannelPointer *ChannelPtr2;
  15447. HTTP2InProxyOutChannel *OutChannel;
  15448. HTTP2InProxyInChannel *InChannel;
  15449. HTTP2InProxyInChannel *InChannel2;
  15450. BYTE *CurrentPosition;
  15451. rpcconn_tunnel_settings *RTS;
  15452. CookieCollection *InProxyCookieCollection;
  15453. HTTP2InProxyVirtualConnection *ExistingConnection;
  15454. HTTP2Cookie NewChannelCookie;
  15455. HTTP2SendContext *EmptyRTS;
  15456. int NonDefaultSelector;
  15457. int DefaultSelector;
  15458. HTTP2SendContext *D3_A2Context;
  15459. HTTP2OtherCmdPacketType PacketType;
  15460. int i;
  15461. ULONG BytesReceivedForAck;
  15462. ULONG WindowForAck;
  15463. HTTP2Cookie CookieForChannel;
  15464. ULONG ServerReceiveWindowSize;
  15465. HTTP2SendContext *SendContext;
  15466. VerifyValidChannelId(ChannelId);
  15467. if (EventStatus == RPC_S_OK)
  15468. {
  15469. // N.B. All recieve packets are guaranteed to be
  15470. // validated up to the common conn packet size
  15471. if (IsRTSPacket(Buffer))
  15472. {
  15473. RpcStatus = CheckPacketForForwarding(Buffer,
  15474. BufferLength,
  15475. fdInProxy
  15476. );
  15477. }
  15478. if (IsRTSPacket(Buffer) && (RpcStatus != RPC_P_PACKET_NEEDS_FORWARDING))
  15479. {
  15480. // RTS packet - check what we need to do with it
  15481. if (IsOtherCmdPacket(Buffer, BufferLength))
  15482. {
  15483. if (IsOutChannel(ChannelId))
  15484. {
  15485. // the only other cmd we expect on the out channel in the proxy are
  15486. // flow control acks
  15487. RpcStatus = ParseAndFreeFlowControlAckPacket (Buffer,
  15488. BufferLength,
  15489. &BytesReceivedForAck,
  15490. &WindowForAck,
  15491. &CookieForChannel
  15492. );
  15493. BufferFreed = TRUE;
  15494. if (RpcStatus != RPC_S_OK)
  15495. return RpcStatus;
  15496. // notify the channel
  15497. ChannelPtr = GetChannelPointerFromId(ChannelId);
  15498. OutChannel = (HTTP2InProxyOutChannel *)ChannelPtr->LockChannelPointer();
  15499. if (OutChannel == NULL)
  15500. return RPC_P_CONNECTION_SHUTDOWN;
  15501. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  15502. WindowForAck
  15503. );
  15504. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  15505. ChannelPtr->UnlockChannelPointer();
  15506. if (RpcStatus != RPC_S_OK)
  15507. return RpcStatus;
  15508. // post another receive
  15509. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  15510. http2ttRaw
  15511. );
  15512. if (RpcStatus != RPC_S_OK)
  15513. return RpcStatus;
  15514. return RPC_P_PACKET_CONSUMED;
  15515. }
  15516. RpcStatus = GetOtherCmdPacketType(Buffer,
  15517. BufferLength,
  15518. &PacketType
  15519. );
  15520. if (RpcStatus == RPC_S_OK)
  15521. {
  15522. switch (PacketType)
  15523. {
  15524. case http2ocptKeepAliveChange:
  15525. RpcStatus = ParseAndFreeKeepAliveChangePacket(Buffer,
  15526. BufferLength,
  15527. &CurrentClientKeepAliveInterval
  15528. );
  15529. BufferFreed = TRUE;
  15530. if (RpcStatus == RPC_S_OK)
  15531. {
  15532. if (CurrentClientKeepAliveInterval == 0)
  15533. CurrentClientKeepAliveInterval = DefaultClientKeepAliveInterval;
  15534. // by now the keep alive interval has been set on the connection.
  15535. // Any new channels will be taken care of by the virtual connection
  15536. // We need to go in and effect this change on the existing channels
  15537. for (i = 0; i < 2; i ++)
  15538. {
  15539. OutChannel = (HTTP2InProxyOutChannel *)OutChannels[0].LockChannelPointer();
  15540. if (OutChannel)
  15541. {
  15542. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  15543. OutChannels[0].UnlockChannelPointer();
  15544. if (RpcStatus != RPC_S_OK)
  15545. break;
  15546. }
  15547. }
  15548. }
  15549. if (RpcStatus == RPC_S_OK)
  15550. {
  15551. // post another receive
  15552. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  15553. http2ttRaw
  15554. );
  15555. if (RpcStatus == RPC_S_OK)
  15556. RpcStatus = RPC_P_PACKET_CONSUMED;
  15557. }
  15558. // return the status code - success or error, both get
  15559. // handled below us
  15560. return RpcStatus;
  15561. break;
  15562. default:
  15563. ASSERT(0);
  15564. return RPC_S_INTERNAL_ERROR;
  15565. }
  15566. }
  15567. }
  15568. MutexCleared = FALSE;
  15569. State.Mutex.Request();
  15570. switch (State.State)
  15571. {
  15572. case http2svClosed:
  15573. // for closed states, we must receive
  15574. // stuff only on the default in channel
  15575. ASSERT(IsDefaultInChannel(ChannelId));
  15576. CurrentPosition = ValidateRTSPacketCommon(Buffer,
  15577. BufferLength
  15578. );
  15579. if (CurrentPosition == NULL)
  15580. {
  15581. RpcStatus = RPC_S_PROTOCOL_ERROR;
  15582. break;
  15583. }
  15584. RTS = (rpcconn_tunnel_settings *)Buffer;
  15585. if ((RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) == 0)
  15586. {
  15587. RpcStatus = ParseAndFreeD1_B1(Buffer,
  15588. BufferLength,
  15589. &ProtocolVersion,
  15590. &EmbeddedConnectionCookie,
  15591. &InChannelCookies[0],
  15592. &ChannelLifetime,
  15593. &AssociationGroupId,
  15594. &CurrentClientKeepAliveInterval
  15595. );
  15596. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  15597. BufferFreed = TRUE;
  15598. if (RpcStatus != RPC_S_OK)
  15599. break;
  15600. if (CurrentClientKeepAliveInterval < MinimumClientKeepAliveInterval)
  15601. {
  15602. RpcStatus = RPC_S_PROTOCOL_ERROR;
  15603. break;
  15604. }
  15605. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svB3W, 1, 0);
  15606. State.State = http2svB3W;
  15607. State.Mutex.Clear();
  15608. MutexCleared = TRUE;
  15609. RpcStatus = InitializeProxySecondLeg();
  15610. if (RpcStatus != RPC_S_OK)
  15611. break;
  15612. RpcStatus = ConnectToServer();
  15613. if (RpcStatus != RPC_S_OK)
  15614. break;
  15615. RpcStatus = SendD1_B2ToServer();
  15616. if (RpcStatus != RPC_S_OK)
  15617. break;
  15618. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  15619. if (RpcStatus != RPC_S_OK)
  15620. break;
  15621. DefaultClientKeepAliveInterval = CurrentClientKeepAliveInterval;
  15622. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  15623. if (OutChannel == NULL)
  15624. {
  15625. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15626. break;
  15627. }
  15628. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  15629. ChannelPtr->UnlockChannelPointer();
  15630. // fall through with the error code
  15631. }
  15632. else
  15633. {
  15634. RpcStatus = ParseAndFreeD2_A1 (Buffer,
  15635. BufferLength,
  15636. &ProtocolVersion,
  15637. &EmbeddedConnectionCookie,
  15638. &InChannelCookies[1], // Old cookie - use InChannelCookies[1]
  15639. // as temporary storage only
  15640. &InChannelCookies[0] // New cookie
  15641. );
  15642. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  15643. BufferFreed = TRUE;
  15644. if (RpcStatus != RPC_S_OK)
  15645. break;
  15646. // caller claims this is recycling for an already existing connection
  15647. // find out this connection
  15648. InProxyCookieCollection = GetInProxyCookieCollection();
  15649. InProxyCookieCollection->LockCollection();
  15650. ExistingConnection = (HTTP2InProxyVirtualConnection *)
  15651. InProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  15652. if (ExistingConnection == NULL || ActAsSeparateMachinesOnWebFarm)
  15653. {
  15654. // no dice. Probably we executed on a different machine on the web farm
  15655. // proceed as a standalone connection
  15656. InProxyCookieCollection->UnlockCollection();
  15657. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svB2W, 1, 0);
  15658. State.State = http2svB2W;
  15659. State.Mutex.Clear();
  15660. MutexCleared = TRUE;
  15661. RpcStatus = InitializeProxySecondLeg();
  15662. if (RpcStatus != RPC_S_OK)
  15663. break;
  15664. RpcStatus = ConnectToServer();
  15665. if (RpcStatus != RPC_S_OK)
  15666. break;
  15667. // posts receive on the server channel as
  15668. // well
  15669. RpcStatus = SendD2_A2ToServer();
  15670. if (RpcStatus != RPC_S_OK)
  15671. break;
  15672. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  15673. if (OutChannel == NULL)
  15674. {
  15675. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15676. break;
  15677. }
  15678. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  15679. ChannelPtr->UnlockChannelPointer();
  15680. if (RpcStatus != RPC_S_OK)
  15681. break;
  15682. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  15683. }
  15684. else
  15685. {
  15686. // detach the in channel from this connection and attach
  15687. // it to the found connection. Grab a reference to it
  15688. // to prevent the case where it goes away underneath us
  15689. // we know that in its current state the connection is single
  15690. // threaded because we are in the completion path of the
  15691. // only async operation
  15692. RpcStatus = ExistingConnection->SetTimeout(DefaultNoResponseTimeout,
  15693. InChannelTimer
  15694. );
  15695. if (RpcStatus != RPC_S_OK)
  15696. break;
  15697. ChannelPtr = GetChannelPointerFromId(ChannelId);
  15698. InChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  15699. // there is no way that somebody detached the channel here
  15700. ASSERT(InChannel);
  15701. // add a reference to keep the channel alive while we disconnect it
  15702. InChannel->AddReference();
  15703. ChannelPtr->UnlockChannelPointer();
  15704. // no need to drain the upcalls - we know we are the only
  15705. // upcall
  15706. ChannelPtr->FreeChannelPointer(
  15707. FALSE, // DrainUpCalls
  15708. FALSE, // CalledFromUpcallContext
  15709. FALSE, // Abort
  15710. RPC_S_OK
  15711. );
  15712. DefaultSelector = ExistingConnection->DefaultInChannelSelector;
  15713. NonDefaultSelector = ExistingConnection->GetNonDefaultInChannelSelector();
  15714. if (ExistingConnection->InChannelCookies[DefaultSelector].Compare (&InChannelCookies[1]))
  15715. {
  15716. // nice try - cookies are different. Ditch the newly established channel
  15717. InProxyCookieCollection->UnlockCollection();
  15718. InChannel->RemoveReference();
  15719. RpcStatus = RPC_S_PROTOCOL_ERROR;
  15720. break;
  15721. }
  15722. InChannel->SetParent(ExistingConnection);
  15723. ExistingConnection->InChannels[NonDefaultSelector].SetChannel(InChannel);
  15724. ExistingConnection->InChannelCookies[NonDefaultSelector].SetCookie(InChannelCookies[0].GetCookie());
  15725. ExistingConnection->InChannelIds[NonDefaultSelector] = ChannelId;
  15726. // check if connection is aborted
  15727. if (ExistingConnection->Aborted.GetInteger() > 0)
  15728. {
  15729. InChannel->Abort(RPC_P_CONNECTION_SHUTDOWN);
  15730. }
  15731. // the extra reference that we added above passes to the existing connection
  15732. // However, below we party on the existing connection and we need to keep it alive
  15733. ExistingConnection->BlockConnectionFromRundown();
  15734. InProxyCookieCollection->UnlockCollection();
  15735. State.Mutex.Clear();
  15736. MutexCleared = TRUE;
  15737. // nuke the rest of the old connection
  15738. // we got to the destructive phase of the abort
  15739. // guard against double aborts
  15740. if (Aborted.Increment() > 1)
  15741. return FALSE;
  15742. // abort the channels
  15743. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  15744. DisconnectChannels(FALSE, // ExemptChannel
  15745. 0 // ExemptChannel id
  15746. );
  15747. delete this;
  15748. // N.B. don't touch the this pointer after here (Duh!)
  15749. ExistingConnection->State.Mutex.Request();
  15750. LogEvent(SU_HTTPv2, EV_STATE, ExistingConnection, IN_CHANNEL_STATE, http2svOpened_A5W, 1, 0);
  15751. ExistingConnection->State.State = http2svOpened_A5W;
  15752. ExistingConnection->State.Mutex.Clear();
  15753. // send D3/A2 to server
  15754. D3_A2Context = AllocateAndInitializeD3_A2(&ExistingConnection->InChannelCookies[NonDefaultSelector]);
  15755. if (D3_A2Context == NULL)
  15756. {
  15757. ExistingConnection->UnblockConnectionFromRundown();
  15758. RpcStatus = RPC_S_OUT_OF_MEMORY;
  15759. break;
  15760. }
  15761. RpcStatus = ExistingConnection->SendTrafficOnDefaultChannel (
  15762. FALSE, // IsInChannel
  15763. D3_A2Context
  15764. );
  15765. if (RpcStatus != RPC_S_OK)
  15766. {
  15767. FreeRTSPacket(D3_A2Context);
  15768. break;
  15769. }
  15770. RpcStatus = ExistingConnection->PostReceiveOnChannel(
  15771. &ExistingConnection->InChannels[NonDefaultSelector],
  15772. http2ttRaw
  15773. );
  15774. ExistingConnection->UnblockConnectionFromRundown();
  15775. // fall through with the obtained RpcStatus
  15776. }
  15777. }
  15778. break;
  15779. case http2svOpened:
  15780. State.Mutex.Clear();
  15781. MutexCleared = TRUE;
  15782. // the only RTS packets we expect in opened state is D2/A5
  15783. RpcStatus = ParseD2_A5 (Buffer,
  15784. BufferLength,
  15785. &NewChannelCookie
  15786. );
  15787. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  15788. {
  15789. RpcFreeBuffer(Buffer);
  15790. break;
  15791. }
  15792. // send D2/A6 immediately, and queue D2/B1 for sending
  15793. // Since D2/A6 is the same as D2/A5 (the packet we just
  15794. // received), we can just forward it
  15795. RpcStatus = ForwardTrafficToDefaultChannel (
  15796. FALSE, // IsInChannel
  15797. Buffer,
  15798. BufferLength
  15799. );
  15800. if (RpcStatus != RPC_S_OK)
  15801. break;
  15802. // we don't own the buffer after a successful send
  15803. BufferFreed = TRUE;
  15804. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  15805. if (OutChannel == NULL)
  15806. {
  15807. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15808. break;
  15809. }
  15810. // Allocate D1/B1
  15811. EmptyRTS = AllocateAndInitializeEmptyRTS ();
  15812. if (EmptyRTS == NULL)
  15813. {
  15814. ChannelPtr->UnlockChannelPointer();
  15815. RpcStatus = RPC_S_OUT_OF_MEMORY;
  15816. break;
  15817. }
  15818. EmptyRTS->Flags = SendContextFlagSendLast;
  15819. RpcStatus = OutChannel->Send(EmptyRTS);
  15820. ChannelPtr->UnlockChannelPointer();
  15821. if (RpcStatus == RPC_S_OK)
  15822. {
  15823. // we're done. There were no queued buffers and D1/B1
  15824. // was sent immediately. When the server aborts its
  15825. // end of the connection, we will close down
  15826. break;
  15827. }
  15828. else if (RpcStatus == ERROR_IO_PENDING)
  15829. {
  15830. // D1/B1 was not sent immediately. When it is sent,
  15831. // the LastPacketSentNotification mechanism will
  15832. // destroy the connection. Return success for know
  15833. RpcStatus = RPC_S_OK;
  15834. }
  15835. else
  15836. {
  15837. // an error occurred during sending. Free the packet and
  15838. // return it back to the caller
  15839. FreeRTSPacket(EmptyRTS);
  15840. }
  15841. break;
  15842. case http2svOpened_A5W:
  15843. // the only RTS packets we expect in opened_A5W state is D3/A5
  15844. RpcStatus = ParseAndFreeD3_A5 (Buffer,
  15845. BufferLength,
  15846. &NewChannelCookie
  15847. );
  15848. BufferFreed = TRUE;
  15849. CancelTimeout(InChannelTimer);
  15850. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  15851. break;
  15852. ASSERT(InChannels[0].IsChannelSet() && InChannels[1].IsChannelSet());
  15853. if (InChannelCookies[GetNonDefaultInChannelSelector()].Compare(&NewChannelCookie))
  15854. {
  15855. // abort
  15856. RpcStatus = RPC_S_PROTOCOL_ERROR;
  15857. break;
  15858. }
  15859. // switch channels and get rid of the old channel
  15860. SwitchDefaultInChannelSelector();
  15861. // drain the queue of buffers received on the non-default
  15862. // channel (new channel) and actually send them on the new default channel
  15863. while ((Buffer = (BYTE *) NonDefaultChannelBufferQueue.TakeOffQueue(&BufferLength)) != NULL)
  15864. {
  15865. RpcStatus = ForwardTrafficToDefaultChannel(FALSE, // IsInChannel
  15866. Buffer,
  15867. BufferLength
  15868. );
  15869. if (RpcStatus != RPC_S_OK)
  15870. {
  15871. RpcFreeBuffer(Buffer);
  15872. // just exit. During abort the rest of the buffers
  15873. // will be freed
  15874. break;
  15875. }
  15876. }
  15877. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  15878. State.State = http2svOpened;
  15879. State.Mutex.Clear();
  15880. MutexCleared = TRUE;
  15881. ChannelPtr = GetChannelPointerFromId(ChannelId);
  15882. InChannel2 = LockDefaultInChannel(&ChannelPtr2);
  15883. if (InChannel2 == NULL)
  15884. {
  15885. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15886. break;
  15887. }
  15888. InChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  15889. if (InChannel == NULL)
  15890. {
  15891. ChannelPtr2->UnlockChannelPointer();
  15892. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15893. break;
  15894. }
  15895. InChannel->TransferReceiveStateToNewChannel(InChannel2);
  15896. ChannelPtr2->UnlockChannelPointer();
  15897. ChannelPtr->UnlockChannelPointer();
  15898. // detach, abort, and release lifetime reference
  15899. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  15900. TRUE, // CalledFromUpcallContext
  15901. TRUE, // Abort
  15902. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  15903. );
  15904. // return success. When the reference for this receive
  15905. // is removed, the channel will go away
  15906. RpcStatus = RPC_S_OK;
  15907. break;
  15908. case http2svB2W:
  15909. if (IsOutChannel(ChannelId) == FALSE)
  15910. {
  15911. ASSERT(0);
  15912. // make sure client doesn't rush things
  15913. RpcStatus = RPC_S_PROTOCOL_ERROR;
  15914. break;
  15915. }
  15916. RpcStatus = ParseAndFreeD2_B2(Buffer,
  15917. BufferLength,
  15918. &ServerReceiveWindowSize
  15919. );
  15920. BufferFreed = TRUE;
  15921. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  15922. break;
  15923. // we know the connection is legitimate - add ourselves
  15924. // to the collection
  15925. InProxyCookieCollection = GetInProxyCookieCollection();
  15926. InProxyCookieCollection->LockCollection();
  15927. ExistingConnection = (HTTP2InProxyVirtualConnection *)
  15928. InProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  15929. if (ExistingConnection != NULL)
  15930. {
  15931. // the only way we will be in this protocol is if
  15932. // we were faking a web farm
  15933. ASSERT (ActAsSeparateMachinesOnWebFarm);
  15934. ProxyConnectionCookie = ExistingConnection->GetCookie();
  15935. ProxyConnectionCookie->AddRefCount();
  15936. }
  15937. else
  15938. {
  15939. // we truly didn't find anything - add ourselves.
  15940. RpcStatus = AddConnectionToCookieCollection ();
  15941. if (RpcStatus != RPC_S_OK)
  15942. {
  15943. InProxyCookieCollection->UnlockCollection();
  15944. break;
  15945. }
  15946. }
  15947. InProxyCookieCollection->UnlockCollection();
  15948. // remember that we are part of the cookie collection now
  15949. IsConnectionInCollection = TRUE;
  15950. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  15951. State.State = http2svOpened;
  15952. State.Mutex.Clear();
  15953. MutexCleared = TRUE;
  15954. // unplug the out channel to get the flow going
  15955. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  15956. if (OutChannel == NULL)
  15957. {
  15958. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  15959. break;
  15960. }
  15961. OutChannel->SetPeerReceiveWindow(ServerReceiveWindowSize);
  15962. RpcStatus = OutChannel->Unplug();
  15963. ChannelPtr->UnlockChannelPointer();
  15964. if (RpcStatus != RPC_S_OK)
  15965. break;
  15966. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  15967. http2ttRaw
  15968. );
  15969. break;
  15970. case http2svB3W:
  15971. ASSERT(IsDefaultOutChannel(ChannelId));
  15972. RpcStatus = ParseAndFreeD1_B3(Buffer,
  15973. BufferLength,
  15974. &ServerReceiveWindowSize,
  15975. &ProtocolVersion
  15976. );
  15977. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  15978. BufferFreed = TRUE;
  15979. if (RpcStatus == RPC_S_OK)
  15980. {
  15981. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRaw);
  15982. if (RpcStatus == RPC_S_OK)
  15983. {
  15984. RpcStatus = AddConnectionToCookieCollection();
  15985. if (RpcStatus == RPC_S_OK)
  15986. {
  15987. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  15988. State.State = http2svOpened;
  15989. State.Mutex.Clear();
  15990. MutexCleared = TRUE;
  15991. OutChannel = (HTTP2InProxyOutChannel *)OutChannels[0].LockChannelPointer();
  15992. if (OutChannel)
  15993. {
  15994. OutChannel->SetPeerReceiveWindow(ServerReceiveWindowSize);
  15995. RpcStatus = OutChannel->Unplug();
  15996. OutChannels[0].UnlockChannelPointer();
  15997. }
  15998. else
  15999. {
  16000. RpcStatus = RPC_P_CONNECTION_CLOSED;
  16001. }
  16002. }
  16003. }
  16004. }
  16005. break;
  16006. default:
  16007. ASSERT(0);
  16008. }
  16009. if (MutexCleared == FALSE)
  16010. State.Mutex.Clear();
  16011. }
  16012. else
  16013. {
  16014. // data packet or RTS packet that needs forwarding. Just forward it
  16015. if (IsDefaultOutChannel(ChannelId))
  16016. {
  16017. // non-RTS packet in any state from out channel
  16018. // is a protocol error
  16019. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16020. }
  16021. else
  16022. {
  16023. if ((State.State == http2svOpened_A5W)
  16024. && (IsDefaultInChannel(ChannelId) == FALSE)
  16025. && (!IsRTSPacket(Buffer)))
  16026. {
  16027. // sends on non-default channel in Opened_A5W state get queued until we
  16028. // receive D3/A5
  16029. State.Mutex.Request();
  16030. if (State.State == http2svOpened_A5W)
  16031. {
  16032. if (NonDefaultChannelBufferQueue.PutOnQueue(Buffer, BufferLength))
  16033. {
  16034. State.Mutex.Clear();
  16035. return RPC_S_OUT_OF_MEMORY;
  16036. }
  16037. State.Mutex.Clear();
  16038. // post a receive for the next buffer
  16039. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16040. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  16041. return RPC_S_OK;
  16042. }
  16043. State.Mutex.Clear();
  16044. }
  16045. SendContext = AllocateAndInitializeContextFromPacket(Buffer,
  16046. BufferLength
  16047. );
  16048. // the buffer is converted to send context. We can't free
  16049. // it directly - we must make sure we free it on failure before exit.
  16050. BufferFreed = TRUE;
  16051. if (SendContext == NULL)
  16052. {
  16053. RpcStatus = RPC_S_OUT_OF_MEMORY;
  16054. }
  16055. else
  16056. {
  16057. ASSERT(SendContext->Flags == 0);
  16058. SendContext->Flags = SendContextFlagProxySend;
  16059. SendContext->UserData = ConvertChannelIdToSendContextUserData(ChannelId);
  16060. // make sure we can find it after that
  16061. ASSERT(MapSendContextUserDataToChannelPtr(SendContext->UserData) != NULL);
  16062. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  16063. SendContext
  16064. );
  16065. if (RpcStatus == RPC_S_OK)
  16066. {
  16067. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16068. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  16069. }
  16070. else
  16071. {
  16072. FreeSendContextAndPossiblyData(SendContext);
  16073. }
  16074. }
  16075. }
  16076. }
  16077. }
  16078. else
  16079. {
  16080. if (IsInChannel(ChannelId) && !IsDefaultInChannel(ChannelId))
  16081. {
  16082. // ignore errors on non-default in channels. They can go
  16083. // away while we are still sending data to the server.
  16084. // We will destroy the connection when the server is done
  16085. RpcStatus = RPC_S_OK;
  16086. }
  16087. else
  16088. {
  16089. // just turn around the error code
  16090. RpcStatus = EventStatus;
  16091. }
  16092. // in failure cases we don't own the buffer
  16093. BufferFreed = TRUE;
  16094. }
  16095. if (BufferFreed == FALSE)
  16096. RpcFreeBuffer(Buffer);
  16097. return RpcStatus;
  16098. }
  16099. void HTTP2InProxyVirtualConnection::DisconnectChannels (
  16100. IN BOOL ExemptChannel,
  16101. IN int ExemptChannelId
  16102. )
  16103. /*++
  16104. Routine Description:
  16105. Disconnects all channels. Must be called from runtime
  16106. or neutral context. Cannot be called from upcall or
  16107. submit context unless an exempt channel is given
  16108. Note that call must synchronize to ensure we're the only
  16109. thread doing the disconnect
  16110. Arguments:
  16111. ExemptChannel - non-zero if ExemptChannelId contains a
  16112. valid exempt channel id. FALSE otherwise.
  16113. ExemptChannelId - if ExemptChannel is non-zero, this argument
  16114. is the id of a channel that will be disconnected, but not
  16115. synchronized with up calls.
  16116. If ExampleChannel is FALSE, this argument is undefined
  16117. Return Value:
  16118. --*/
  16119. {
  16120. BYTE *Buffer;
  16121. UINT BufferLength;
  16122. State.Mutex.Request();
  16123. if (State.State == http2svOpened_A5W)
  16124. {
  16125. while ((Buffer = (BYTE *) NonDefaultChannelBufferQueue.TakeOffQueue(&BufferLength)) != NULL)
  16126. {
  16127. RpcFreeBuffer(Buffer);
  16128. }
  16129. }
  16130. State.Mutex.Clear();
  16131. HTTP2ProxyVirtualConnection::DisconnectChannels(ExemptChannel,
  16132. ExemptChannelId
  16133. );
  16134. }
  16135. RPC_STATUS HTTP2InProxyVirtualConnection::AllocateAndInitializeInChannel (
  16136. IN void *ConnectionParameter,
  16137. OUT HTTP2InProxyInChannel **ReturnInChannel,
  16138. OUT void **IISContext
  16139. )
  16140. /*++
  16141. Routine Description:
  16142. Allocates and initializes the in proxy in channel.
  16143. Arguments:
  16144. ConnectionParameter - really an EXTENSION_CONTROL_BLOCK
  16145. ReturnInChannel - on success the created in channel.
  16146. IISContext - on output, the IISChannel pointer used as
  16147. connection context with IIS.
  16148. Return Value:
  16149. RPC_S_OK or RPC_S_* for error
  16150. --*/
  16151. {
  16152. ULONG MemorySize;
  16153. BYTE *MemoryBlock, *CurrentBlock;
  16154. HTTP2InProxyInChannel *InChannel;
  16155. HTTP2ProxyReceiver *ProxyReceiver;
  16156. HTTP2PingReceiver *PingReceiver;
  16157. HTTP2IISTransportChannel *IISChannel;
  16158. BOOL ProxyReceiverNeedsCleanup;
  16159. BOOL PingReceiverNeedsCleanup;
  16160. BOOL IISChannelNeedsCleanup;
  16161. RPC_STATUS RpcStatus;
  16162. // alocate the in channel
  16163. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyInChannel)
  16164. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver)
  16165. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  16166. + SIZE_OF_OBJECT_AND_PADDING(HTTP2IISTransportChannel);
  16167. MemoryBlock = (BYTE *) new char [MemorySize];
  16168. CurrentBlock = MemoryBlock;
  16169. if (CurrentBlock == NULL)
  16170. return RPC_S_OUT_OF_MEMORY;
  16171. InChannel = (HTTP2InProxyInChannel *) MemoryBlock;
  16172. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyInChannel);
  16173. ProxyReceiver = (HTTP2ProxyReceiver *) CurrentBlock;
  16174. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver);
  16175. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  16176. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  16177. IISChannel = (HTTP2IISTransportChannel *)CurrentBlock;
  16178. // all memory blocks are allocated. Go and initialize them. Use explicit
  16179. // placement
  16180. ProxyReceiverNeedsCleanup = FALSE;
  16181. PingReceiverNeedsCleanup = FALSE;
  16182. IISChannelNeedsCleanup = FALSE;
  16183. RpcStatus = RPC_S_OK;
  16184. IISChannel = new (IISChannel) HTTP2IISTransportChannel (ConnectionParameter);
  16185. IISChannelNeedsCleanup = TRUE;
  16186. ProxyReceiver = new (ProxyReceiver) HTTP2ProxyReceiver (HTTP2InProxyReceiveWindow,
  16187. &RpcStatus);
  16188. if (RpcStatus != RPC_S_OK)
  16189. {
  16190. ProxyReceiver->HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  16191. goto AbortAndExit;
  16192. }
  16193. IISChannel->SetUpperChannel(ProxyReceiver);
  16194. ProxyReceiver->SetLowerChannel(IISChannel);
  16195. ProxyReceiverNeedsCleanup = TRUE;
  16196. PingReceiver = new (PingReceiver) HTTP2PingReceiver(TRUE);
  16197. if (RpcStatus != RPC_S_OK)
  16198. {
  16199. PingReceiver->HTTP2PingReceiver::~HTTP2PingReceiver();
  16200. goto AbortAndExit;
  16201. }
  16202. ProxyReceiver->SetUpperChannel(PingReceiver);
  16203. PingReceiver->SetLowerChannel(ProxyReceiver);
  16204. PingReceiverNeedsCleanup = TRUE;
  16205. InChannel = new (InChannel) HTTP2InProxyInChannel (this, &RpcStatus);
  16206. if (RpcStatus != RPC_S_OK)
  16207. {
  16208. InChannel->HTTP2InProxyInChannel::~HTTP2InProxyInChannel();
  16209. goto AbortAndExit;
  16210. }
  16211. PingReceiver->SetUpperChannel(InChannel);
  16212. InChannel->SetLowerChannel(PingReceiver);
  16213. IISChannel->SetTopChannel(InChannel);
  16214. ProxyReceiver->SetTopChannel(InChannel);
  16215. PingReceiver->SetTopChannel(InChannel);
  16216. ASSERT(RpcStatus == RPC_S_OK);
  16217. *ReturnInChannel = InChannel;
  16218. *IISContext = IISChannel;
  16219. goto CleanupAndExit;
  16220. AbortAndExit:
  16221. if (PingReceiverNeedsCleanup)
  16222. {
  16223. PingReceiver->Abort(RpcStatus);
  16224. PingReceiver->FreeObject();
  16225. }
  16226. else if (ProxyReceiverNeedsCleanup)
  16227. {
  16228. ProxyReceiver->Abort(RpcStatus);
  16229. ProxyReceiver->FreeObject();
  16230. }
  16231. else if (IISChannelNeedsCleanup)
  16232. {
  16233. IISChannel->Abort(RpcStatus);
  16234. IISChannel->FreeObject();
  16235. }
  16236. if (MemoryBlock)
  16237. delete [] MemoryBlock;
  16238. CleanupAndExit:
  16239. return RpcStatus;
  16240. }
  16241. RPC_STATUS HTTP2InProxyVirtualConnection::AllocateAndInitializeOutChannel (
  16242. OUT HTTP2InProxyOutChannel **ReturnOutChannel
  16243. )
  16244. /*++
  16245. Routine Description:
  16246. Allocates and initializes the in proxy out channel.
  16247. Arguments:
  16248. ReturnInChannel - on success the created in channel.
  16249. Return Value:
  16250. RPC_S_OK or RPC_S_* for error
  16251. --*/
  16252. {
  16253. ULONG MemorySize;
  16254. BYTE *MemoryBlock, *CurrentBlock;
  16255. HTTP2InProxyOutChannel *OutChannel;
  16256. HTTP2ProxyPlugChannel *PlugChannel;
  16257. HTTP2FlowControlSender *FlowControlSender;
  16258. HTTP2ProxySocketTransportChannel *RawChannel;
  16259. WS_HTTP2_CONNECTION *RawConnection;
  16260. BOOL PlugChannelNeedsCleanup;
  16261. BOOL FlowControlSenderNeedsCleanup;
  16262. BOOL RawChannelNeedsCleanup;
  16263. BOOL RawConnectionNeedsCleanup;
  16264. RPC_STATUS RpcStatus;
  16265. // alocate the in channel
  16266. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyOutChannel)
  16267. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel)
  16268. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  16269. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel)
  16270. + sizeof(WS_HTTP2_CONNECTION);
  16271. MemoryBlock = (BYTE *) new char [MemorySize];
  16272. CurrentBlock = MemoryBlock;
  16273. if (CurrentBlock == NULL)
  16274. return RPC_S_OUT_OF_MEMORY;
  16275. OutChannel = (HTTP2InProxyOutChannel *) MemoryBlock;
  16276. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyOutChannel);
  16277. PlugChannel = (HTTP2ProxyPlugChannel *) CurrentBlock;
  16278. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel);
  16279. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  16280. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  16281. RawChannel = (HTTP2ProxySocketTransportChannel *)CurrentBlock;
  16282. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel);
  16283. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  16284. RawConnection->HeaderRead = FALSE;
  16285. RawConnection->ReadHeaderFn = HTTP2ReadHttpLegacyResponse;
  16286. // all memory blocks are allocated. Go and initialize them. Use explicit
  16287. // placement
  16288. PlugChannelNeedsCleanup = FALSE;
  16289. FlowControlSenderNeedsCleanup = FALSE;
  16290. RawChannelNeedsCleanup = FALSE;
  16291. RawConnectionNeedsCleanup = FALSE;
  16292. RawConnection->Initialize();
  16293. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  16294. RawConnectionNeedsCleanup = TRUE;
  16295. RpcStatus = RPC_S_OK;
  16296. RawChannel = new (RawChannel) HTTP2ProxySocketTransportChannel (RawConnection, &RpcStatus);
  16297. if (RpcStatus != RPC_S_OK)
  16298. {
  16299. RawChannel->HTTP2ProxySocketTransportChannel::~HTTP2ProxySocketTransportChannel();
  16300. goto AbortAndExit;
  16301. }
  16302. RawConnection->Channel = RawChannel;
  16303. RawChannelNeedsCleanup = TRUE;
  16304. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  16305. FALSE, // SendToRuntime
  16306. &RpcStatus
  16307. );
  16308. if (RpcStatus != RPC_S_OK)
  16309. {
  16310. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  16311. goto AbortAndExit;
  16312. }
  16313. RawChannel->SetUpperChannel(FlowControlSender);
  16314. FlowControlSender->SetLowerChannel(RawChannel);
  16315. FlowControlSenderNeedsCleanup = TRUE;
  16316. PlugChannel = new (PlugChannel) HTTP2ProxyPlugChannel (&RpcStatus);
  16317. if (RpcStatus != RPC_S_OK)
  16318. {
  16319. PlugChannel->HTTP2ProxyPlugChannel::~HTTP2ProxyPlugChannel();
  16320. goto AbortAndExit;
  16321. }
  16322. FlowControlSender->SetUpperChannel(PlugChannel);
  16323. PlugChannel->SetLowerChannel(FlowControlSender);
  16324. PlugChannelNeedsCleanup = TRUE;
  16325. OutChannel = new (OutChannel) HTTP2InProxyOutChannel (this,
  16326. RawConnection,
  16327. &RpcStatus);
  16328. if (RpcStatus != RPC_S_OK)
  16329. {
  16330. OutChannel->HTTP2InProxyOutChannel::~HTTP2InProxyOutChannel();
  16331. goto AbortAndExit;
  16332. }
  16333. PlugChannel->SetUpperChannel(OutChannel);
  16334. OutChannel->SetLowerChannel(PlugChannel);
  16335. RawChannel->SetTopChannel(OutChannel);
  16336. FlowControlSender->SetTopChannel(OutChannel);
  16337. PlugChannel->SetTopChannel(OutChannel);
  16338. ASSERT(RpcStatus == RPC_S_OK);
  16339. *ReturnOutChannel = OutChannel;
  16340. goto CleanupAndExit;
  16341. AbortAndExit:
  16342. if (PlugChannelNeedsCleanup)
  16343. {
  16344. PlugChannel->Abort(RpcStatus);
  16345. PlugChannel->FreeObject();
  16346. }
  16347. else if (FlowControlSenderNeedsCleanup)
  16348. {
  16349. FlowControlSender->Abort(RpcStatus);
  16350. FlowControlSender->FreeObject();
  16351. }
  16352. else if (RawChannelNeedsCleanup)
  16353. {
  16354. RawChannel->Abort(RpcStatus);
  16355. RawChannel->FreeObject();
  16356. }
  16357. else if (RawConnectionNeedsCleanup)
  16358. {
  16359. RawConnection->RealAbort();
  16360. }
  16361. if (MemoryBlock)
  16362. delete [] MemoryBlock;
  16363. CleanupAndExit:
  16364. return RpcStatus;
  16365. }
  16366. RPC_STATUS HTTP2InProxyVirtualConnection::ConnectToServer (
  16367. void
  16368. )
  16369. /*++
  16370. Routine Description:
  16371. Connects to the server
  16372. Arguments:
  16373. Return Value:
  16374. RPC_S_OK or RPC_S_* for error
  16375. --*/
  16376. {
  16377. HTTP2ChannelPointer *ChannelPtr;
  16378. HTTP2InProxyOutChannel *OutChannel;
  16379. RPC_STATUS RpcStatus;
  16380. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16381. // we don't have any async operations to abort the connection
  16382. // yet - the out channel must be there
  16383. ASSERT(OutChannel);
  16384. RpcStatus = OutChannel->InitializeRawConnection(ServerName,
  16385. ServerPort,
  16386. ConnectionTimeout,
  16387. ProxyCallbackInterface->IsValidMachineFn
  16388. );
  16389. ChannelPtr->UnlockChannelPointer();
  16390. return RpcStatus;
  16391. }
  16392. RPC_STATUS HTTP2InProxyVirtualConnection::SendD1_B2ToServer (
  16393. void
  16394. )
  16395. /*++
  16396. Routine Description:
  16397. Sends D1/B2 to server
  16398. Arguments:
  16399. Return Value:
  16400. RPC_S_OK or RPC_S_* for error
  16401. --*/
  16402. {
  16403. HTTP2ChannelPointer *ChannelPtr;
  16404. HTTP2InProxyOutChannel *OutChannel;
  16405. RPC_STATUS RpcStatus;
  16406. HTTP2SendContext *SendContext;
  16407. BOOL SendSucceeded = FALSE;
  16408. SendContext = AllocateAndInitializeD1_B2(ProtocolVersion,
  16409. &EmbeddedConnectionCookie,
  16410. &InChannelCookies[0],
  16411. HTTP2InProxyReceiveWindow,
  16412. IISConnectionTimeout,
  16413. &AssociationGroupId,
  16414. &ClientAddress
  16415. );
  16416. if (SendContext == NULL)
  16417. return RPC_S_OUT_OF_MEMORY;
  16418. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16419. // we don't have any async operations to abort the connection
  16420. // yet - the out channel must be there
  16421. ASSERT(OutChannel);
  16422. RpcStatus = OutChannel->Send(SendContext);
  16423. if (RpcStatus == RPC_S_OK)
  16424. {
  16425. SendSucceeded = TRUE;
  16426. RpcStatus = OutChannel->Receive(http2ttRaw);
  16427. }
  16428. ChannelPtr->UnlockChannelPointer();
  16429. if (SendSucceeded == FALSE)
  16430. {
  16431. FreeRTSPacket(SendContext);
  16432. }
  16433. return RpcStatus;
  16434. }
  16435. RPC_STATUS HTTP2InProxyVirtualConnection::SendD2_A2ToServer (
  16436. void
  16437. )
  16438. /*++
  16439. Routine Description:
  16440. Sends D2/A2 to server
  16441. Arguments:
  16442. Return Value:
  16443. RPC_S_OK or RPC_S_* for error
  16444. --*/
  16445. {
  16446. HTTP2ChannelPointer *ChannelPtr;
  16447. HTTP2InProxyOutChannel *OutChannel;
  16448. RPC_STATUS RpcStatus;
  16449. HTTP2SendContext *SendContext;
  16450. BOOL SendSucceeded = FALSE;
  16451. SendContext = AllocateAndInitializeD2_A2(ProtocolVersion,
  16452. &EmbeddedConnectionCookie,
  16453. &InChannelCookies[1],
  16454. &InChannelCookies[0],
  16455. HTTP2InProxyReceiveWindow,
  16456. IISConnectionTimeout
  16457. );
  16458. if (SendContext == NULL)
  16459. return RPC_S_OUT_OF_MEMORY;
  16460. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16461. // we don't have any async operations to abort the connection
  16462. // yet - the out channel must be there
  16463. ASSERT(OutChannel);
  16464. RpcStatus = OutChannel->Send(SendContext);
  16465. if (RpcStatus == RPC_S_OK)
  16466. {
  16467. SendSucceeded = TRUE;
  16468. RpcStatus = OutChannel->Receive(http2ttRaw);
  16469. }
  16470. ChannelPtr->UnlockChannelPointer();
  16471. if (SendSucceeded == FALSE)
  16472. {
  16473. FreeRTSPacket(SendContext);
  16474. }
  16475. return RpcStatus;
  16476. }
  16477. /*********************************************************************
  16478. HTTP2OutProxyInChannel
  16479. *********************************************************************/
  16480. RPC_STATUS HTTP2OutProxyInChannel::ForwardFlowControlAck (
  16481. IN ULONG BytesReceivedForAck,
  16482. IN ULONG WindowForAck
  16483. )
  16484. /*++
  16485. Routine Description:
  16486. Forwards a flow control ack back to the server
  16487. Arguments:
  16488. BytesReceivedForAck - the bytes received when the ACK was issued
  16489. WindowForAck - the free window when the ACK was issued.
  16490. Return Value:
  16491. RPC_S_OK or RPC_S_*
  16492. --*/
  16493. {
  16494. return ForwardFlowControlAckOnThisChannel(BytesReceivedForAck,
  16495. WindowForAck,
  16496. FALSE // NonChannelData
  16497. );
  16498. }
  16499. /*********************************************************************
  16500. HTTP2OutProxyOutChannel
  16501. *********************************************************************/
  16502. RPC_STATUS HTTP2OutProxyOutChannel::LastPacketSentNotification (
  16503. IN HTTP2SendContext *LastSendContext
  16504. )
  16505. /*++
  16506. Routine Description:
  16507. When a lower channel wants to notify the top
  16508. channel that the last packet has been sent,
  16509. they call this function. Must be called from
  16510. an upcall/neutral context. Only flow control
  16511. senders support last packet notifications
  16512. Arguments:
  16513. LastSendContext - the context for the last send
  16514. Return Value:
  16515. The value to return to the bottom channel
  16516. --*/
  16517. {
  16518. HTTP2OutProxyVirtualConnection *VirtualConnection;
  16519. ASSERT(LastSendContext->Flags & SendContextFlagSendLast);
  16520. ASSERT((LastSendContext->UserData == oplptD4_A10)
  16521. || (LastSendContext->UserData == oplptD5_B3));
  16522. VirtualConnection = (HTTP2OutProxyVirtualConnection *)LockParentPointer();
  16523. // if the connection was already aborted, nothing to do
  16524. if (VirtualConnection == NULL)
  16525. return RPC_P_PACKET_CONSUMED;
  16526. // we know the parent will disconnect from us in their
  16527. // notification
  16528. VirtualConnection->LastPacketSentNotification(ChannelId,
  16529. LastSendContext);
  16530. if (LastSendContext->UserData == oplptD5_B3)
  16531. {
  16532. // if we are about to send D5_B3, this is the last packet
  16533. // on the channel. Detach from the parent and return an
  16534. // error
  16535. UnlockParentPointer();
  16536. DrainUpcallsAndFreeParent();
  16537. }
  16538. // just shutdown the connection or what has remained of it
  16539. // (only this channel in the D5_B3 case)
  16540. return RPC_P_CONNECTION_SHUTDOWN;
  16541. }
  16542. void HTTP2OutProxyOutChannel::PingTrafficSentNotify (
  16543. IN ULONG PingTrafficSize
  16544. )
  16545. /*++
  16546. Routine Description:
  16547. Notifies a channel that ping traffic has been sent.
  16548. Arguments:
  16549. PingTrafficSize - the size of the ping traffic sent.
  16550. --*/
  16551. {
  16552. BOOL Result;
  16553. AccumulatedPingTraffic += PingTrafficSize;
  16554. if (AccumulatedPingTraffic >= AccumulatedPingTrafficNotifyThreshold)
  16555. {
  16556. Result = PingTrafficSentNotifyServer (AccumulatedPingTraffic);
  16557. if (Result)
  16558. AccumulatedPingTraffic = 0;
  16559. }
  16560. }
  16561. BOOL HTTP2OutProxyOutChannel::PingTrafficSentNotifyServer (
  16562. IN ULONG PingTrafficSize
  16563. )
  16564. /*++
  16565. Routine Description:
  16566. Sends a notification to the server that ping traffic originated
  16567. at the out proxy has been sent. This allows to server to do
  16568. proper accounting for when to recycle the out channel.
  16569. Arguments:
  16570. PingTrafficSize - the size of the ping traffic to notify the
  16571. server about.
  16572. Return Value:
  16573. Non-zero if the notification was sent successfully.
  16574. 0 otherwise.
  16575. --*/
  16576. {
  16577. HTTP2OutProxyVirtualConnection *VirtualConnection;
  16578. BOOL Result;
  16579. VirtualConnection = (HTTP2OutProxyVirtualConnection *)LockParentPointer();
  16580. // if the connection was already aborted, nothing to do
  16581. if (VirtualConnection == NULL)
  16582. return TRUE;
  16583. Result = VirtualConnection->PingTrafficSentNotifyServer(PingTrafficSize);
  16584. UnlockParentPointer();
  16585. return Result;
  16586. }
  16587. /*********************************************************************
  16588. HTTP2OutProxyVirtualConnection
  16589. *********************************************************************/
  16590. RPC_STATUS HTTP2OutProxyVirtualConnection::InitializeProxyFirstLeg (
  16591. IN USHORT *ServerAddress,
  16592. IN USHORT *ServerPort,
  16593. IN void *ConnectionParameter,
  16594. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface,
  16595. void **IISContext
  16596. )
  16597. /*++
  16598. Routine Description:
  16599. Initialize the proxy.
  16600. Arguments:
  16601. ServerAddress - unicode pointer string to the server network address.
  16602. ServerPort - unicode pointer string to the server port
  16603. ConnectionParameter - the extension control block in this case
  16604. ProxyCallbackInterface - a callback interface to the proxy to perform
  16605. various proxy specific functions.
  16606. IISContext - on output (success only) it must be initialized to
  16607. the bottom IISChannel for the InProxy.
  16608. Return Value:
  16609. RPC_S_OK or other RPC_S_* errors for error
  16610. --*/
  16611. {
  16612. RPC_STATUS RpcStatus;
  16613. HTTP2OutProxyOutChannel *NewOutChannel;
  16614. int OutChannelId;
  16615. int ServerAddressLength; // in characters + terminating 0
  16616. // initialize out channel
  16617. RpcStatus = AllocateAndInitializeOutChannel(ConnectionParameter,
  16618. &NewOutChannel,
  16619. IISContext
  16620. );
  16621. if (RpcStatus != RPC_S_OK)
  16622. return RpcStatus;
  16623. SetFirstOutChannel(NewOutChannel);
  16624. this->ProxyCallbackInterface = ProxyCallbackInterface;
  16625. this->ConnectionParameter = ConnectionParameter;
  16626. ServerAddressLength = RpcpStringLength(ServerAddress) + 1;
  16627. ServerName = new RPC_CHAR [ServerAddressLength];
  16628. if (ServerName == NULL)
  16629. return RPC_S_OUT_OF_MEMORY;
  16630. RpcpMemoryCopy(ServerName, ServerAddress, ServerAddressLength * 2);
  16631. RpcStatus = EndpointToPortNumber(ServerPort, this->ServerPort);
  16632. return RpcStatus;
  16633. }
  16634. RPC_STATUS HTTP2OutProxyVirtualConnection::StartProxy (
  16635. void
  16636. )
  16637. /*++
  16638. Routine Description:
  16639. Kicks off listening on the proxy
  16640. Arguments:
  16641. Return Value:
  16642. RPC_S_OK or RPC_S_* for error
  16643. --*/
  16644. {
  16645. HTTP2OutProxyOutChannel *Channel;
  16646. HTTP2ChannelPointer *ChannelPtr;
  16647. RPC_STATUS RpcStatus;
  16648. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svClosed, 1, 0);
  16649. State.State = http2svClosed; // move to closed state expecting the opening RTS packet
  16650. Channel = LockDefaultOutChannel(&ChannelPtr);
  16651. ASSERT(Channel != NULL); // we cannot be disconnected now
  16652. RpcStatus = Channel->Receive(http2ttRaw);
  16653. ChannelPtr->UnlockChannelPointer();
  16654. return RpcStatus;
  16655. }
  16656. RPC_STATUS HTTP2OutProxyVirtualConnection::InitializeProxySecondLeg (
  16657. void
  16658. )
  16659. /*++
  16660. Routine Description:
  16661. Initialize the proxy.
  16662. Arguments:
  16663. Return Value:
  16664. RPC_S_OK or other RPC_S_* errors for error
  16665. --*/
  16666. {
  16667. RPC_STATUS RpcStatus;
  16668. HTTP2OutProxyInChannel *NewInChannel;
  16669. int InChannelId;
  16670. // initialize in channel
  16671. RpcStatus = AllocateAndInitializeInChannel(
  16672. &NewInChannel
  16673. );
  16674. if (RpcStatus != RPC_S_OK)
  16675. {
  16676. Abort();
  16677. return RpcStatus;
  16678. }
  16679. SetFirstInChannel(NewInChannel);
  16680. RpcStatus = ProxyCallbackInterface->GetConnectionTimeoutFn(&IISConnectionTimeout);
  16681. if (RpcStatus != RPC_S_OK)
  16682. {
  16683. Abort();
  16684. return RpcStatus;
  16685. }
  16686. IISConnectionTimeout *= 1000;
  16687. return RpcStatus;
  16688. }
  16689. RPC_STATUS HTTP2OutProxyVirtualConnection::ReceiveComplete (
  16690. IN RPC_STATUS EventStatus,
  16691. IN BYTE *Buffer,
  16692. IN UINT BufferLength,
  16693. IN int ChannelId
  16694. )
  16695. /*++
  16696. Routine Description:
  16697. Called by lower layers to indicate receive complete
  16698. Arguments:
  16699. EventStatus - RPC_S_OK for success or RPC_S_* for error
  16700. Buffer - buffer received
  16701. BufferLength - length of buffer received
  16702. ChannelId - which channel completed the operation
  16703. Return Value:
  16704. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  16705. be hidden from the runtime.
  16706. RPC_S_OK if the packet was processed successfully.
  16707. RPC_S_* error if there was an error while processing the
  16708. packet.
  16709. --*/
  16710. {
  16711. RPC_STATUS RpcStatus;
  16712. BOOL BufferFreed = FALSE;
  16713. BOOL MutexCleared;
  16714. ULONG ChannelLifetime;
  16715. ULONG Ignored;
  16716. HTTP2ChannelPointer *ChannelPtr;
  16717. HTTP2ChannelPointer *ChannelPtr2;
  16718. HTTP2OutProxyOutChannel *OutChannel;
  16719. HTTP2OutProxyOutChannel *OutChannel2;
  16720. CookieCollection *OutProxyCookieCollection;
  16721. BYTE *CurrentPosition;
  16722. rpcconn_tunnel_settings *RTS;
  16723. HTTP2SendContext *D5_A4Context;
  16724. HTTP2OutProxyVirtualConnection *ExistingConnection;
  16725. int NonDefaultSelector;
  16726. int DefaultSelector;
  16727. HTTP2SendContext *D4_A10Context;
  16728. BOOL IsAckOrNak;
  16729. HTTP2SendContext *D5_B3Context;
  16730. ULONG BytesReceivedForAck;
  16731. ULONG WindowForAck;
  16732. HTTP2Cookie CookieForChannel;
  16733. ULONG ClientReceiveWindowSize;
  16734. HTTP2SendContext *SendContext;
  16735. VerifyValidChannelId(ChannelId);
  16736. if (EventStatus == RPC_S_OK)
  16737. {
  16738. // N.B. All recieve packets are guaranteed to be
  16739. // validated up to the common conn packet size
  16740. if (IsRTSPacket(Buffer))
  16741. {
  16742. RpcStatus = HTTPTransInfo->CreateThread();
  16743. if (RpcStatus != RPC_S_OK)
  16744. {
  16745. RpcFreeBuffer(Buffer);
  16746. return RpcStatus;
  16747. }
  16748. RpcStatus = CheckPacketForForwarding(Buffer,
  16749. BufferLength,
  16750. fdOutProxy
  16751. );
  16752. }
  16753. if (IsRTSPacket(Buffer) && (RpcStatus != RPC_P_PACKET_NEEDS_FORWARDING))
  16754. {
  16755. // RTS packet - check what we need to do with it
  16756. if (IsOtherCmdPacket(Buffer, BufferLength))
  16757. {
  16758. // the only other cmd packets we expect in the proxy are
  16759. // flow control acks
  16760. RpcStatus = ParseAndFreeFlowControlAckPacketWithDestination (Buffer,
  16761. BufferLength,
  16762. fdOutProxy,
  16763. &BytesReceivedForAck,
  16764. &WindowForAck,
  16765. &CookieForChannel
  16766. );
  16767. BufferFreed = TRUE;
  16768. if (RpcStatus != RPC_S_OK)
  16769. return RpcStatus;
  16770. // notify the flow control sender about the ack
  16771. OutChannel = (HTTP2OutProxyOutChannel *)MapCookieToAnyChannelPointer(
  16772. &CookieForChannel,
  16773. &ChannelPtr
  16774. );
  16775. if (OutChannel)
  16776. {
  16777. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  16778. WindowForAck
  16779. );
  16780. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  16781. ChannelPtr->UnlockChannelPointer();
  16782. }
  16783. if (RpcStatus != RPC_S_OK)
  16784. return RpcStatus;
  16785. // post another receive
  16786. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  16787. http2ttRaw
  16788. );
  16789. if (RpcStatus != RPC_S_OK)
  16790. return RpcStatus;
  16791. return RPC_P_PACKET_CONSUMED;
  16792. }
  16793. MutexCleared = FALSE;
  16794. State.Mutex.Request();
  16795. switch (State.State)
  16796. {
  16797. case http2svClosed:
  16798. // for closed states, we must receive
  16799. // stuff only on the default out (client) channel
  16800. ASSERT(IsDefaultOutChannel(ChannelId));
  16801. CurrentPosition = ValidateRTSPacketCommon(Buffer,
  16802. BufferLength
  16803. );
  16804. if (CurrentPosition == NULL)
  16805. {
  16806. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16807. break;
  16808. }
  16809. RTS = (rpcconn_tunnel_settings *)Buffer;
  16810. if ((RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) == 0)
  16811. {
  16812. RpcStatus = ParseAndFreeD1_A1(Buffer,
  16813. BufferLength,
  16814. &ProtocolVersion,
  16815. &EmbeddedConnectionCookie,
  16816. &OutChannelCookies[0],
  16817. &ClientReceiveWindowSize
  16818. );
  16819. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  16820. BufferFreed = TRUE;
  16821. if (RpcStatus == RPC_S_OK)
  16822. {
  16823. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svC1W, 1, 0);
  16824. State.State = http2svC1W;
  16825. State.Mutex.Clear();
  16826. MutexCleared = TRUE;
  16827. RpcStatus = InitializeProxySecondLeg();
  16828. if (RpcStatus != RPC_S_OK)
  16829. break;
  16830. RpcStatus = ConnectToServer();
  16831. if (RpcStatus != RPC_S_OK)
  16832. break;
  16833. RpcStatus = SendHeaderToClient();
  16834. if (RpcStatus != RPC_S_OK)
  16835. break;
  16836. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16837. if (OutChannel == NULL)
  16838. {
  16839. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16840. break;
  16841. }
  16842. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  16843. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  16844. ChannelPtr->UnlockChannelPointer();
  16845. // zero out the in channel cookie
  16846. InChannelCookies[0].ZeroOut();
  16847. if (RpcStatus != RPC_S_OK)
  16848. break;
  16849. RpcStatus = SendD1_A3ToClient();
  16850. if (RpcStatus != RPC_S_OK)
  16851. break;
  16852. RpcStatus = SendD1_A2ToServer(DefaultChannelLifetime);
  16853. }
  16854. }
  16855. else
  16856. {
  16857. RpcStatus = ParseAndFreeD4_A3 (Buffer,
  16858. BufferLength,
  16859. &ProtocolVersion,
  16860. &EmbeddedConnectionCookie,
  16861. &OutChannelCookies[1], // Old cookie - use OutChannelCookies[1]
  16862. // as temporary storage only
  16863. &OutChannelCookies[0], // New cookie
  16864. &ClientReceiveWindowSize
  16865. );
  16866. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  16867. BufferFreed = TRUE;
  16868. if (RpcStatus != RPC_S_OK)
  16869. break;
  16870. // caller claims this is recycling for an already existing connection
  16871. // find out this connection
  16872. OutProxyCookieCollection = GetOutProxyCookieCollection();
  16873. OutProxyCookieCollection->LockCollection();
  16874. ExistingConnection = (HTTP2OutProxyVirtualConnection *)
  16875. OutProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  16876. if (ExistingConnection == NULL || ActAsSeparateMachinesOnWebFarm)
  16877. {
  16878. // no dice. Probably we executed on a different machine on the web farm
  16879. // proceed as a standalone connection
  16880. OutProxyCookieCollection->UnlockCollection();
  16881. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svA11W, 1, 0);
  16882. State.State = http2svA11W;
  16883. State.Mutex.Clear();
  16884. MutexCleared = TRUE;
  16885. RpcStatus = InitializeProxySecondLeg();
  16886. if (RpcStatus != RPC_S_OK)
  16887. break;
  16888. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16889. // we cannot be aborted here
  16890. ASSERT(OutChannel);
  16891. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  16892. // make sure no packets (RTS or other) go out until
  16893. // we get out D4/A11 and send out the header response
  16894. OutChannel->SetStrongPlug();
  16895. ChannelPtr->UnlockChannelPointer();
  16896. // zero out the in channel cookie
  16897. InChannelCookies[0].ZeroOut();
  16898. RpcStatus = ConnectToServer();
  16899. if (RpcStatus != RPC_S_OK)
  16900. break;
  16901. RpcStatus = SendD4_A4ToServer(DefaultChannelLifetime);
  16902. if (RpcStatus != RPC_S_OK)
  16903. break;
  16904. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  16905. http2ttRaw
  16906. );
  16907. }
  16908. else
  16909. {
  16910. // detach the out channel from this connection and attach
  16911. // it to the found connection. Grab a reference to it
  16912. // to prevent the case where it goes away underneath us
  16913. // we know that in its current state the connection is single
  16914. // threaded because we are in the completion path of the
  16915. // only async operation
  16916. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16917. OutChannel = (HTTP2OutProxyOutChannel *)ChannelPtr->LockChannelPointer();
  16918. // there is no way that somebody detached the channel here
  16919. ASSERT(OutChannel);
  16920. // add a reference to keep the channel alive while we disconnect it
  16921. OutChannel->AddReference();
  16922. ChannelPtr->UnlockChannelPointer();
  16923. // no need to drain the upcalls - we know we are the only
  16924. // upcall
  16925. ChannelPtr->FreeChannelPointer(
  16926. FALSE, // DrainUpCalls
  16927. FALSE, // CalledFromUpcallContext
  16928. FALSE, // Abort
  16929. RPC_S_OK
  16930. );
  16931. DefaultSelector = ExistingConnection->DefaultOutChannelSelector;
  16932. NonDefaultSelector = ExistingConnection->GetNonDefaultOutChannelSelector();
  16933. if (ExistingConnection->OutChannelCookies[DefaultSelector].Compare (&OutChannelCookies[1]))
  16934. {
  16935. // nice try - cookies are different. Ditch the newly established channel
  16936. OutProxyCookieCollection->UnlockCollection();
  16937. OutChannel->RemoveReference();
  16938. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16939. break;
  16940. }
  16941. OutChannel2 = ExistingConnection->LockDefaultOutChannel(&ChannelPtr2);
  16942. if (OutChannel2 == NULL)
  16943. {
  16944. OutProxyCookieCollection->UnlockCollection();
  16945. OutChannel->RemoveReference();
  16946. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16947. break;
  16948. }
  16949. ClientReceiveWindowSize = OutChannel2->GetPeerReceiveWindow();
  16950. ChannelPtr2->UnlockChannelPointer();
  16951. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  16952. OutChannel->SetParent(ExistingConnection);
  16953. ExistingConnection->OutChannels[NonDefaultSelector].SetChannel(OutChannel);
  16954. ExistingConnection->OutChannelCookies[NonDefaultSelector].SetCookie(OutChannelCookies[0].GetCookie());
  16955. ExistingConnection->OutChannelIds[NonDefaultSelector] = ChannelId;
  16956. // check if connection is aborted
  16957. if (ExistingConnection->Aborted.GetInteger() > 0)
  16958. {
  16959. OutChannel->Abort(RPC_P_CONNECTION_SHUTDOWN);
  16960. }
  16961. // the extra reference that we added above passes to the existing connection
  16962. // However, below we party on the existing connection and we need to keep it alive
  16963. ExistingConnection->BlockConnectionFromRundown();
  16964. OutProxyCookieCollection->UnlockCollection();
  16965. State.Mutex.Clear();
  16966. MutexCleared = TRUE;
  16967. // nuke the rest of the old connection
  16968. // we got to the destructive phase of the abort
  16969. // guard against double aborts
  16970. if (Aborted.Increment() <= 1)
  16971. {
  16972. // abort the channels
  16973. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  16974. DisconnectChannels(FALSE, // ExemptChannel
  16975. 0 // ExemptChannel id
  16976. );
  16977. delete this;
  16978. // N.B. don't touch the this pointer after here
  16979. }
  16980. // post another receive on the new channel
  16981. RpcStatus = PostReceiveOnChannel (&(ExistingConnection->OutChannels[NonDefaultSelector]),
  16982. http2ttRaw);
  16983. if (RpcStatus != RPC_S_OK)
  16984. {
  16985. ExistingConnection->UnblockConnectionFromRundown();
  16986. break;
  16987. }
  16988. ExistingConnection->State.Mutex.Request();
  16989. LogEvent(SU_HTTPv2, EV_STATE, ExistingConnection, OUT_CHANNEL_STATE, http2svOpened_B1W, 1, 0);
  16990. ExistingConnection->State.State = http2svOpened_B1W;
  16991. ExistingConnection->State.Mutex.Clear();
  16992. // send D5/A4 to server
  16993. D5_A4Context = AllocateAndInitializeD5_A4(&ExistingConnection->OutChannelCookies[NonDefaultSelector]);
  16994. if (D5_A4Context == NULL)
  16995. {
  16996. ExistingConnection->UnblockConnectionFromRundown();
  16997. RpcStatus = RPC_S_OUT_OF_MEMORY;
  16998. break;
  16999. }
  17000. RpcStatus = ExistingConnection->SendTrafficOnDefaultChannel (
  17001. TRUE, // IsInChannel
  17002. D5_A4Context
  17003. );
  17004. if (RpcStatus != RPC_S_OK)
  17005. FreeRTSPacket(D5_A4Context);
  17006. ExistingConnection->UnblockConnectionFromRundown();
  17007. // fall through with the obtained RpcStatus
  17008. }
  17009. }
  17010. break;
  17011. case http2svOpened:
  17012. State.Mutex.Clear();
  17013. MutexCleared = TRUE;
  17014. // the only RTS packets we expect in opened state is D4/A9
  17015. RpcStatus = ParseAndFreeD4_A9 (Buffer,
  17016. BufferLength
  17017. );
  17018. BufferFreed = TRUE;
  17019. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  17020. break;
  17021. // queue D4/A10 for sending
  17022. // First, allocate D4/A10
  17023. D4_A10Context = AllocateAndInitializeD4_A10 ();
  17024. if (D4_A10Context == NULL)
  17025. {
  17026. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17027. break;
  17028. }
  17029. D4_A10Context->Flags = SendContextFlagSendLast;
  17030. D4_A10Context->UserData = oplptD4_A10;
  17031. RpcStatus = SendTrafficOnDefaultChannel (FALSE, // IsInChannel
  17032. D4_A10Context);
  17033. if (RpcStatus == RPC_S_OK)
  17034. {
  17035. // we're done. There were no queued buffers and D4/A10
  17036. // was sent immediately. Close down
  17037. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17038. break;
  17039. }
  17040. else if (RpcStatus == ERROR_IO_PENDING)
  17041. {
  17042. // D4/A10 was not sent immediately. When it is sent,
  17043. // the LastPacketSentNotification mechanism will
  17044. // destroy the connection. Return success for know
  17045. RpcStatus = RPC_S_OK;
  17046. }
  17047. else
  17048. {
  17049. // an error occurred during sending. Free the packet and
  17050. // return error back to the caller
  17051. FreeRTSPacket(D4_A10Context);
  17052. }
  17053. break;
  17054. case http2svC1W:
  17055. ASSERT(IsDefaultInChannel(ChannelId));
  17056. RpcStatus = ParseD1_C1(Buffer,
  17057. BufferLength,
  17058. &ProtocolVersion,
  17059. &Ignored, // InProxyReceiveWindowSize
  17060. &Ignored // InProxyConnectionTimeout
  17061. );
  17062. if (RpcStatus == RPC_S_OK)
  17063. {
  17064. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  17065. RpcStatus = AddConnectionToCookieCollection();
  17066. if (RpcStatus == RPC_S_OK)
  17067. {
  17068. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  17069. State.State = http2svOpened;
  17070. State.Mutex.Clear();
  17071. MutexCleared = TRUE;
  17072. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17073. if (OutChannel != NULL)
  17074. {
  17075. RpcStatus = OutChannel->ForwardTraffic(Buffer,
  17076. BufferLength
  17077. );
  17078. if (RpcStatus == RPC_S_OK)
  17079. {
  17080. BufferFreed = TRUE;
  17081. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  17082. if (RpcStatus == RPC_S_OK)
  17083. {
  17084. RpcStatus = OutChannel->Unplug();
  17085. }
  17086. }
  17087. ChannelPtr->UnlockChannelPointer();
  17088. }
  17089. else
  17090. RpcStatus = RPC_P_CONNECTION_CLOSED;
  17091. }
  17092. }
  17093. break;
  17094. case http2svOpened_CliW:
  17095. break;
  17096. case http2svOpened_B1W:
  17097. State.Mutex.Clear();
  17098. MutexCleared = TRUE;
  17099. // the only RTS packets we expect in opened state is D5/B1 or D2/B2
  17100. RpcStatus = ParseAndFreeD5_B1orB2 (Buffer,
  17101. BufferLength,
  17102. &IsAckOrNak
  17103. );
  17104. BufferFreed = TRUE;
  17105. if (RpcStatus != RPC_S_OK)
  17106. break;
  17107. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17108. if (OutChannel == NULL)
  17109. {
  17110. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17111. break;
  17112. }
  17113. // keep an extra reference for after we detach the
  17114. // channel
  17115. OutChannel->AddReference();
  17116. ChannelPtr->UnlockChannelPointer();
  17117. if (IsAckOrNak == FALSE)
  17118. {
  17119. // Nak - nuke the non-default channel
  17120. // and move to state opened
  17121. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  17122. FALSE, // CalledFromUpcallContext
  17123. TRUE, // Abort
  17124. RPC_S_PROTOCOL_ERROR
  17125. );
  17126. // switch to state opened
  17127. State.Mutex.Request();
  17128. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  17129. State.State = http2svOpened;
  17130. State.Mutex.Clear();
  17131. break;
  17132. }
  17133. SwitchDefaultOutChannelSelector();
  17134. // Send D5/B3 to client
  17135. D5_B3Context = AllocateAndInitializeD5_B3();
  17136. if (D5_B3Context == NULL)
  17137. {
  17138. OutChannel->RemoveReference();
  17139. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17140. break;
  17141. }
  17142. D5_B3Context->Flags = SendContextFlagSendLast;
  17143. D5_B3Context->UserData = oplptD5_B3;
  17144. RpcStatus = OutChannel->Send(D5_B3Context);
  17145. if (RpcStatus == RPC_S_OK)
  17146. {
  17147. // synchronous send. Abort and detach the old channel
  17148. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  17149. FALSE, // CalledFromUpcallContext
  17150. TRUE, // Abort
  17151. RPC_P_CONNECTION_SHUTDOWN
  17152. );
  17153. }
  17154. else if (RpcStatus == ERROR_IO_PENDING)
  17155. {
  17156. // async send. Just release our reference
  17157. // and return success
  17158. RpcStatus = RPC_S_OK;
  17159. }
  17160. else
  17161. {
  17162. // failed to send. Abort all
  17163. FreeRTSPacket(D5_B3Context);
  17164. OutChannel->Abort(RpcStatus);
  17165. OutChannel->RemoveReference();
  17166. break;
  17167. }
  17168. // release the extra reference
  17169. OutChannel->RemoveReference();
  17170. // switch to state opened
  17171. State.Mutex.Request();
  17172. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  17173. State.State = http2svOpened;
  17174. State.Mutex.Clear();
  17175. // unplug the newly created channel
  17176. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17177. if (OutChannel == NULL)
  17178. {
  17179. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17180. break;
  17181. }
  17182. RpcStatus = OutChannel->Unplug();
  17183. if (RpcStatus != RPC_S_OK)
  17184. {
  17185. ChannelPtr->UnlockChannelPointer();
  17186. break;
  17187. }
  17188. // send the header response to the client
  17189. RpcStatus = SendHeaderToClient();
  17190. if (RpcStatus != RPC_S_OK)
  17191. {
  17192. ChannelPtr->UnlockChannelPointer();
  17193. break;
  17194. }
  17195. // set the connection timeout
  17196. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  17197. ChannelPtr->UnlockChannelPointer();
  17198. if (RpcStatus != RPC_S_OK)
  17199. break;
  17200. // post another receive on the channel
  17201. RpcStatus = PostReceiveOnDefaultChannel(TRUE, // IsInChannel
  17202. http2ttRaw);
  17203. // fall through with the new error code
  17204. break;
  17205. case http2svA11W:
  17206. if (IsOutChannel(ChannelId) == FALSE)
  17207. {
  17208. ASSERT(0);
  17209. // make sure client doesn't rush things
  17210. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17211. break;
  17212. }
  17213. RpcStatus = ParseAndFreeD4_A11(Buffer,
  17214. BufferLength
  17215. );
  17216. BufferFreed = TRUE;
  17217. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  17218. break;
  17219. // now that we know the new channel is legit, add it to the
  17220. // collection
  17221. OutProxyCookieCollection = GetOutProxyCookieCollection();
  17222. OutProxyCookieCollection->LockCollection();
  17223. ExistingConnection = (HTTP2OutProxyVirtualConnection *)
  17224. OutProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  17225. if (ExistingConnection != NULL)
  17226. {
  17227. // the only way we will be in this protocol is if
  17228. // we were faking a web farm
  17229. ASSERT (ActAsSeparateMachinesOnWebFarm);
  17230. ProxyConnectionCookie = ExistingConnection->GetCookie();
  17231. ProxyConnectionCookie->AddRefCount();
  17232. }
  17233. else
  17234. {
  17235. // we truly didn't find anything - add ourselves.
  17236. RpcStatus = AddConnectionToCookieCollection ();
  17237. if (RpcStatus != RPC_S_OK)
  17238. {
  17239. OutProxyCookieCollection->UnlockCollection();
  17240. break;
  17241. }
  17242. }
  17243. OutProxyCookieCollection->UnlockCollection();
  17244. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  17245. State.State = http2svOpened;
  17246. State.Mutex.Clear();
  17247. MutexCleared = TRUE;
  17248. // unplug the out channel to get the flow going
  17249. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  17250. if (OutChannel == NULL)
  17251. {
  17252. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17253. break;
  17254. }
  17255. RpcStatus = SendHeaderToClient();
  17256. if (RpcStatus != RPC_S_OK)
  17257. {
  17258. ChannelPtr->UnlockChannelPointer();
  17259. break;
  17260. }
  17261. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  17262. if (RpcStatus != RPC_S_OK)
  17263. {
  17264. ChannelPtr->UnlockChannelPointer();
  17265. break;
  17266. }
  17267. RpcStatus = OutChannel->Unplug();
  17268. ChannelPtr->UnlockChannelPointer();
  17269. break;
  17270. case http2svOpened_A5W:
  17271. break;
  17272. case http2svB2W:
  17273. break;
  17274. default:
  17275. ASSERT(0);
  17276. }
  17277. if (MutexCleared == FALSE)
  17278. State.Mutex.Clear();
  17279. }
  17280. else
  17281. {
  17282. // data packet or RTS packet that needs forwarding. Just forward it
  17283. ASSERT (IsDefaultInChannel(ChannelId));
  17284. if (State.State == http2svC1W)
  17285. {
  17286. // non-RTS packet or forward RTS packet in C1W state from out channel
  17287. // is a protocol error
  17288. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17289. }
  17290. else
  17291. {
  17292. SendContext = AllocateAndInitializeContextFromPacket(Buffer,
  17293. BufferLength
  17294. );
  17295. // the buffer is converted to send context. We can't free
  17296. // it directly - we must make sure we free it on failure before exit.
  17297. BufferFreed = TRUE;
  17298. if (SendContext == NULL)
  17299. {
  17300. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17301. }
  17302. else
  17303. {
  17304. ASSERT(SendContext->Flags == 0);
  17305. SendContext->Flags = SendContextFlagProxySend;
  17306. SendContext->UserData = ConvertChannelIdToSendContextUserData(ChannelId);
  17307. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  17308. SendContext
  17309. );
  17310. if (RpcStatus == RPC_S_OK)
  17311. {
  17312. ChannelPtr = GetChannelPointerFromId(ChannelId);
  17313. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  17314. }
  17315. else
  17316. {
  17317. FreeSendContextAndPossiblyData(SendContext);
  17318. }
  17319. }
  17320. }
  17321. }
  17322. }
  17323. else
  17324. {
  17325. // just turn around the error code
  17326. RpcStatus = EventStatus;
  17327. // in failure cases we don't own the buffer
  17328. BufferFreed = TRUE;
  17329. }
  17330. if (BufferFreed == FALSE)
  17331. RpcFreeBuffer(Buffer);
  17332. return RpcStatus;
  17333. }
  17334. BOOL HTTP2OutProxyVirtualConnection::PingTrafficSentNotifyServer (
  17335. IN ULONG PingTrafficSize
  17336. )
  17337. /*++
  17338. Routine Description:
  17339. Sends a notification to the server that ping traffic originated
  17340. at the out proxy has been sent. This allows to server to do
  17341. proper accounting for when to recycle the out channel.
  17342. The function is called from neutral upcall context. It can't
  17343. return an error, and it can't abort.
  17344. Arguments:
  17345. PingTrafficSize - the size of the ping traffic to notify the
  17346. server about.
  17347. Return Value:
  17348. Non-zero if the notification was sent successfully.
  17349. 0 otherwise.
  17350. --*/
  17351. {
  17352. HTTP2SendContext *PingTrafficSentContext;
  17353. RPC_STATUS RpcStatus;
  17354. PingTrafficSentContext = AllocateAndInitializePingTrafficSentNotifyPacket (PingTrafficSize);
  17355. if (PingTrafficSentContext == NULL)
  17356. return FALSE;
  17357. RpcStatus = SendTrafficOnDefaultChannel (TRUE, // IsInChannel
  17358. PingTrafficSentContext
  17359. );
  17360. if (RpcStatus != RPC_S_OK)
  17361. {
  17362. FreeRTSPacket(PingTrafficSentContext);
  17363. return FALSE;
  17364. }
  17365. else
  17366. return TRUE;
  17367. }
  17368. RPC_STATUS HTTP2OutProxyVirtualConnection::AllocateAndInitializeInChannel (
  17369. OUT HTTP2OutProxyInChannel **ReturnInChannel
  17370. )
  17371. /*++
  17372. Routine Description:
  17373. Allocates and initializes the out proxy in channel.
  17374. Arguments:
  17375. ReturnInChannel - on success the created in channel.
  17376. Return Value:
  17377. RPC_S_OK or RPC_S_* for error
  17378. --*/
  17379. {
  17380. ULONG MemorySize;
  17381. BYTE *MemoryBlock, *CurrentBlock;
  17382. HTTP2OutProxyInChannel *InChannel;
  17383. HTTP2ProxyReceiver *ProxyReceiver;
  17384. HTTP2ProxySocketTransportChannel *RawChannel;
  17385. WS_HTTP2_CONNECTION *RawConnection;
  17386. BOOL ProxyReceiverNeedsCleanup;
  17387. BOOL RawChannelNeedsCleanup;
  17388. BOOL RawConnectionNeedsCleanup;
  17389. RPC_STATUS RpcStatus;
  17390. // alocate the in channel
  17391. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyInChannel)
  17392. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver)
  17393. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel)
  17394. + sizeof(WS_HTTP2_CONNECTION);
  17395. MemoryBlock = (BYTE *) new char [MemorySize];
  17396. CurrentBlock = MemoryBlock;
  17397. if (CurrentBlock == NULL)
  17398. return RPC_S_OUT_OF_MEMORY;
  17399. InChannel = (HTTP2OutProxyInChannel *) MemoryBlock;
  17400. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyInChannel);
  17401. ProxyReceiver = (HTTP2ProxyReceiver *) CurrentBlock;
  17402. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver);
  17403. RawChannel = (HTTP2ProxySocketTransportChannel *)CurrentBlock;
  17404. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel);
  17405. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  17406. RawConnection->HeaderRead = FALSE;
  17407. RawConnection->ReadHeaderFn = HTTP2ReadHttpLegacyResponse;
  17408. // all memory blocks are allocated. Go and initialize them. Use explicit
  17409. // placement
  17410. ProxyReceiverNeedsCleanup = FALSE;
  17411. RawChannelNeedsCleanup = FALSE;
  17412. RawConnectionNeedsCleanup = FALSE;
  17413. RawConnection->Initialize();
  17414. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  17415. RawConnectionNeedsCleanup = TRUE;
  17416. RpcStatus = RPC_S_OK;
  17417. RawChannel = new (RawChannel) HTTP2ProxySocketTransportChannel (RawConnection, &RpcStatus);
  17418. if (RpcStatus != RPC_S_OK)
  17419. {
  17420. RawChannel->HTTP2ProxySocketTransportChannel::~HTTP2ProxySocketTransportChannel();
  17421. goto AbortAndExit;
  17422. }
  17423. RawConnection->Channel = RawChannel;
  17424. RawChannelNeedsCleanup = TRUE;
  17425. ProxyReceiver = new (ProxyReceiver) HTTP2ProxyReceiver (HTTP2OutProxyReceiveWindow,
  17426. &RpcStatus);
  17427. if (RpcStatus != RPC_S_OK)
  17428. {
  17429. ProxyReceiver->HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  17430. goto AbortAndExit;
  17431. }
  17432. RawChannel->SetUpperChannel(ProxyReceiver);
  17433. ProxyReceiver->SetLowerChannel(RawChannel);
  17434. ProxyReceiverNeedsCleanup = TRUE;
  17435. InChannel = new (InChannel) HTTP2OutProxyInChannel (this,
  17436. RawConnection,
  17437. &RpcStatus);
  17438. if (RpcStatus != RPC_S_OK)
  17439. {
  17440. InChannel->HTTP2OutProxyInChannel::~HTTP2OutProxyInChannel();
  17441. goto AbortAndExit;
  17442. }
  17443. ProxyReceiver->SetUpperChannel(InChannel);
  17444. InChannel->SetLowerChannel(ProxyReceiver);
  17445. RawChannel->SetTopChannel(InChannel);
  17446. ProxyReceiver->SetTopChannel(InChannel);
  17447. ASSERT(RpcStatus == RPC_S_OK);
  17448. *ReturnInChannel = InChannel;
  17449. goto CleanupAndExit;
  17450. AbortAndExit:
  17451. if (ProxyReceiverNeedsCleanup)
  17452. {
  17453. ProxyReceiver->Abort(RpcStatus);
  17454. ProxyReceiver->FreeObject();
  17455. }
  17456. else if (RawChannelNeedsCleanup)
  17457. {
  17458. RawChannel->Abort(RpcStatus);
  17459. RawChannel->FreeObject();
  17460. }
  17461. else if (RawConnectionNeedsCleanup)
  17462. {
  17463. RawConnection->RealAbort();
  17464. }
  17465. if (MemoryBlock)
  17466. delete [] MemoryBlock;
  17467. CleanupAndExit:
  17468. return RpcStatus;
  17469. }
  17470. RPC_STATUS HTTP2OutProxyVirtualConnection::AllocateAndInitializeOutChannel (
  17471. IN void *ConnectionParameter,
  17472. OUT HTTP2OutProxyOutChannel **ReturnOutChannel,
  17473. OUT void **IISContext
  17474. )
  17475. /*++
  17476. Routine Description:
  17477. Allocates and initializes the out proxy out channel.
  17478. Arguments:
  17479. ConnectionParameter - really an EXTENSION_CONTROL_BLOCK
  17480. ReturnOutChannel - on success the created out channel.
  17481. IISContext - on output, the IISChannel pointer used as
  17482. connection context with IIS.
  17483. Return Value:
  17484. RPC_S_OK or RPC_S_* for error
  17485. --*/
  17486. {
  17487. ULONG MemorySize;
  17488. BYTE *MemoryBlock, *CurrentBlock;
  17489. HTTP2OutProxyOutChannel *OutChannel;
  17490. HTTP2ProxyPlugChannel *PlugChannel;
  17491. HTTP2FlowControlSender *FlowControlSender;
  17492. HTTP2PingOriginator *PingOriginator;
  17493. HTTP2PingReceiver *PingReceiver;
  17494. HTTP2IISSenderTransportChannel *IISChannel;
  17495. BOOL PlugChannelNeedsCleanup;
  17496. BOOL FlowControlSenderNeedsCleanup;
  17497. BOOL PingOriginatorNeedsCleanup;
  17498. BOOL PingReceiverNeedsCleanup;
  17499. BOOL IISChannelNeedsCleanup;
  17500. RPC_STATUS RpcStatus;
  17501. // alocate the in channel
  17502. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyOutChannel)
  17503. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel)
  17504. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  17505. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator)
  17506. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  17507. + SIZE_OF_OBJECT_AND_PADDING(HTTP2IISSenderTransportChannel)
  17508. ;
  17509. MemoryBlock = (BYTE *) new char [MemorySize];
  17510. CurrentBlock = MemoryBlock;
  17511. if (CurrentBlock == NULL)
  17512. return RPC_S_OUT_OF_MEMORY;
  17513. OutChannel = (HTTP2OutProxyOutChannel *) MemoryBlock;
  17514. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyOutChannel);
  17515. PlugChannel = (HTTP2ProxyPlugChannel *) CurrentBlock;
  17516. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel);
  17517. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  17518. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  17519. PingOriginator = (HTTP2PingOriginator *)CurrentBlock;
  17520. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator);
  17521. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  17522. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  17523. IISChannel = (HTTP2IISSenderTransportChannel *)CurrentBlock;
  17524. // all memory blocks are allocated. Go and initialize them. Use explicit
  17525. // placement
  17526. PlugChannelNeedsCleanup = FALSE;
  17527. FlowControlSenderNeedsCleanup = FALSE;
  17528. PingOriginatorNeedsCleanup = FALSE;
  17529. PingReceiverNeedsCleanup = FALSE;
  17530. IISChannelNeedsCleanup = FALSE;
  17531. RpcStatus = RPC_S_OK;
  17532. IISChannel = new (IISChannel) HTTP2IISSenderTransportChannel (ConnectionParameter, &RpcStatus);
  17533. if (RpcStatus != RPC_S_OK)
  17534. {
  17535. IISChannel->HTTP2IISSenderTransportChannel::~HTTP2IISSenderTransportChannel();
  17536. goto AbortAndExit;
  17537. }
  17538. IISChannelNeedsCleanup = TRUE;
  17539. PingReceiver = new (PingReceiver) HTTP2PingReceiver (FALSE);
  17540. IISChannel->SetUpperChannel(PingReceiver);
  17541. PingReceiver->SetLowerChannel(IISChannel);
  17542. PingReceiverNeedsCleanup = TRUE;
  17543. PingOriginator = new (PingOriginator) HTTP2PingOriginator (
  17544. TRUE // NotifyTopChannelForPings
  17545. );
  17546. PingReceiver->SetUpperChannel(PingOriginator);
  17547. PingOriginator->SetLowerChannel(PingReceiver);
  17548. PingOriginatorNeedsCleanup = TRUE;
  17549. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  17550. FALSE, // SendToRuntime
  17551. &RpcStatus
  17552. );
  17553. if (RpcStatus != RPC_S_OK)
  17554. {
  17555. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  17556. goto AbortAndExit;
  17557. }
  17558. PingOriginator->SetUpperChannel(FlowControlSender);
  17559. FlowControlSender->SetLowerChannel(PingOriginator);
  17560. FlowControlSenderNeedsCleanup = TRUE;
  17561. PlugChannel = new (PlugChannel) HTTP2ProxyPlugChannel (&RpcStatus);
  17562. if (RpcStatus != RPC_S_OK)
  17563. {
  17564. PlugChannel->HTTP2ProxyPlugChannel::~HTTP2ProxyPlugChannel();
  17565. goto AbortAndExit;
  17566. }
  17567. FlowControlSender->SetUpperChannel(PlugChannel);
  17568. PlugChannel->SetLowerChannel(FlowControlSender);
  17569. PlugChannelNeedsCleanup = TRUE;
  17570. OutChannel = new (OutChannel) HTTP2OutProxyOutChannel (this, &RpcStatus);
  17571. if (RpcStatus != RPC_S_OK)
  17572. {
  17573. OutChannel->HTTP2OutProxyOutChannel::~HTTP2OutProxyOutChannel();
  17574. goto AbortAndExit;
  17575. }
  17576. PlugChannel->SetUpperChannel(OutChannel);
  17577. OutChannel->SetLowerChannel(PlugChannel);
  17578. IISChannel->SetTopChannel(OutChannel);
  17579. PingOriginator->SetTopChannel(OutChannel);
  17580. PingReceiver->SetTopChannel(OutChannel);
  17581. FlowControlSender->SetTopChannel(OutChannel);
  17582. PlugChannel->SetTopChannel(OutChannel);
  17583. ASSERT(RpcStatus == RPC_S_OK);
  17584. *ReturnOutChannel = OutChannel;
  17585. *IISContext = IISChannel;
  17586. goto CleanupAndExit;
  17587. AbortAndExit:
  17588. if (PlugChannelNeedsCleanup)
  17589. {
  17590. PlugChannel->Abort(RpcStatus);
  17591. PlugChannel->FreeObject();
  17592. }
  17593. else if (FlowControlSenderNeedsCleanup)
  17594. {
  17595. FlowControlSender->Abort(RpcStatus);
  17596. FlowControlSender->FreeObject();
  17597. }
  17598. else if (PingOriginatorNeedsCleanup)
  17599. {
  17600. PingOriginator->Abort(RpcStatus);
  17601. PingOriginator->FreeObject();
  17602. }
  17603. else if (PingReceiverNeedsCleanup)
  17604. {
  17605. PingReceiver->Abort(RpcStatus);
  17606. PingReceiver->FreeObject();
  17607. }
  17608. else if (IISChannelNeedsCleanup)
  17609. {
  17610. IISChannel->Abort(RpcStatus);
  17611. IISChannel->FreeObject();
  17612. }
  17613. if (MemoryBlock)
  17614. delete [] MemoryBlock;
  17615. CleanupAndExit:
  17616. return RpcStatus;
  17617. }
  17618. RPC_STATUS HTTP2OutProxyVirtualConnection::ConnectToServer (
  17619. void
  17620. )
  17621. /*++
  17622. Routine Description:
  17623. Connects to the server and sends D1/A2
  17624. Arguments:
  17625. Return Value:
  17626. RPC_S_OK or RPC_S_* for error
  17627. --*/
  17628. {
  17629. HTTP2ChannelPointer *ChannelPtr;
  17630. HTTP2OutProxyInChannel *InChannel;
  17631. RPC_STATUS RpcStatus;
  17632. InChannel = LockDefaultInChannel(&ChannelPtr);
  17633. // we cannot be aborted right now
  17634. ASSERT(InChannel != NULL);
  17635. RpcStatus = InChannel->InitializeRawConnection(ServerName,
  17636. ServerPort,
  17637. ConnectionTimeout,
  17638. ProxyCallbackInterface->IsValidMachineFn
  17639. );
  17640. if (RpcStatus == RPC_S_OK)
  17641. {
  17642. RpcStatus = InChannel->Receive(http2ttRaw);
  17643. }
  17644. ChannelPtr->UnlockChannelPointer();
  17645. return RpcStatus;
  17646. }
  17647. RPC_STATUS HTTP2OutProxyVirtualConnection::SendHeaderToClient (
  17648. void
  17649. )
  17650. /*++
  17651. Routine Description:
  17652. Sends response header to client
  17653. Arguments:
  17654. Return Value:
  17655. RPC_S_OK or RPC_S_* for error
  17656. --*/
  17657. {
  17658. RPC_STATUS RpcStatus;
  17659. HTTP2SendContext *SendContext;
  17660. SendContext = AllocateAndInitializeResponseHeader();
  17661. if (SendContext == NULL)
  17662. return RPC_S_OUT_OF_MEMORY;
  17663. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  17664. SendContext
  17665. );
  17666. if (RpcStatus != RPC_S_OK)
  17667. RpcFreeBuffer(SendContext);
  17668. return RpcStatus;
  17669. }
  17670. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD1_A3ToClient (
  17671. void
  17672. )
  17673. /*++
  17674. Routine Description:
  17675. Sends D1/A3 to client
  17676. Arguments:
  17677. Return Value:
  17678. RPC_S_OK or RPC_S_* for error
  17679. --*/
  17680. {
  17681. RPC_STATUS RpcStatus;
  17682. HTTP2SendContext *SendContext;
  17683. SendContext = AllocateAndInitializeD1_A3(IISConnectionTimeout);
  17684. if (SendContext == NULL)
  17685. return RPC_S_OUT_OF_MEMORY;
  17686. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  17687. SendContext
  17688. );
  17689. if (RpcStatus != RPC_S_OK)
  17690. FreeRTSPacket(SendContext);
  17691. return RpcStatus;
  17692. }
  17693. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD1_A2ToServer (
  17694. IN ULONG ChannelLifetime
  17695. )
  17696. /*++
  17697. Routine Description:
  17698. Sends D1/A3 to client
  17699. Arguments:
  17700. ChannelLifetime - the lifetime of the channel as established by
  17701. the client.
  17702. Return Value:
  17703. RPC_S_OK or RPC_S_* for error
  17704. --*/
  17705. {
  17706. RPC_STATUS RpcStatus;
  17707. HTTP2SendContext *SendContext;
  17708. SendContext = AllocateAndInitializeD1_A2 (ProtocolVersion,
  17709. &EmbeddedConnectionCookie,
  17710. &OutChannelCookies[0],
  17711. ChannelLifetime,
  17712. ProxyReceiveWindowSize
  17713. );
  17714. if (SendContext == NULL)
  17715. return RPC_S_OUT_OF_MEMORY;
  17716. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  17717. SendContext
  17718. );
  17719. if (RpcStatus != RPC_S_OK)
  17720. FreeRTSPacket(SendContext);
  17721. return RpcStatus;
  17722. }
  17723. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD4_A4ToServer (
  17724. IN ULONG ChannelLifetime
  17725. )
  17726. /*++
  17727. Routine Description:
  17728. Sends D1/A3 to client
  17729. Arguments:
  17730. ChannelLifetime - the lifetime of the channel as established by
  17731. the client.
  17732. Return Value:
  17733. RPC_S_OK or RPC_S_* for error
  17734. --*/
  17735. {
  17736. RPC_STATUS RpcStatus;
  17737. HTTP2SendContext *SendContext;
  17738. SendContext = AllocateAndInitializeD4_A4 (ProtocolVersion,
  17739. &EmbeddedConnectionCookie,
  17740. &OutChannelCookies[1],
  17741. &OutChannelCookies[0],
  17742. ChannelLifetime,
  17743. ProxyReceiveWindowSize,
  17744. IISConnectionTimeout
  17745. );
  17746. if (SendContext == NULL)
  17747. return RPC_S_OUT_OF_MEMORY;
  17748. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  17749. SendContext
  17750. );
  17751. if (RpcStatus != RPC_S_OK)
  17752. FreeRTSPacket(SendContext);
  17753. return RpcStatus;
  17754. }
  17755. void HTTP2OutProxyVirtualConnection::LastPacketSentNotification (
  17756. IN int ChannelId,
  17757. IN HTTP2SendContext *LastSendContext
  17758. )
  17759. /*++
  17760. Routine Description:
  17761. When a channel wants to notify the virtual connection
  17762. that the last packet has been sent, they call this function.
  17763. Must be called from an upcall/neutral context. Only flow control
  17764. senders generated past packet notifications
  17765. Arguments:
  17766. ChannelId - the channelfor which this notification is.
  17767. LastSendContext - the send context for the last send
  17768. Return Value:
  17769. --*/
  17770. {
  17771. HTTP2ChannelPointer *ChannelPtr;
  17772. ASSERT(LastSendContext->Flags & SendContextFlagSendLast);
  17773. ASSERT((LastSendContext->UserData == oplptD4_A10)
  17774. || (LastSendContext->UserData == oplptD5_B3));
  17775. if (LastSendContext->UserData == oplptD5_B3)
  17776. {
  17777. ChannelPtr = GetChannelPointerFromId(ChannelId);
  17778. // Detach the old channel
  17779. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  17780. TRUE, // CalledFromUpcallContext
  17781. FALSE, // Abort
  17782. RPC_S_OK
  17783. );
  17784. }
  17785. }
  17786. /*********************************************************************
  17787. HTTP2ServerInChannel
  17788. *********************************************************************/
  17789. RPC_STATUS HTTP2ServerInChannel::QueryLocalAddress (
  17790. IN OUT void *Buffer,
  17791. IN OUT unsigned long *BufferSize,
  17792. OUT unsigned long *AddressFormat
  17793. )
  17794. /*++
  17795. Routine Description:
  17796. Returns the local IP address of a channel.
  17797. Arguments:
  17798. Buffer - The buffer that will receive the output address
  17799. BufferSize - the size of the supplied Buffer on input. On output the
  17800. number of bytes written to the buffer. If the buffer is too small
  17801. to receive all the output data, ERROR_MORE_DATA is returned,
  17802. nothing is written to the buffer, and BufferSize is set to
  17803. the size of the buffer needed to return all the data.
  17804. AddressFormat - a constant indicating the format of the returned address.
  17805. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  17806. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  17807. Return Value:
  17808. RPC_S_OK or other RPC_S_* errors for error
  17809. --*/
  17810. {
  17811. RPC_STATUS RpcStatus;
  17812. WS_HTTP2_CONNECTION *RawConnection;
  17813. RpcStatus = BeginSimpleSubmitAsync();
  17814. if (RpcStatus != RPC_S_OK)
  17815. return RpcStatus;
  17816. RawConnection = GetRawConnection();
  17817. RpcStatus = TCP_QueryLocalAddress(RawConnection,
  17818. Buffer,
  17819. BufferSize,
  17820. AddressFormat
  17821. );
  17822. FinishSubmitAsync();
  17823. return RpcStatus;
  17824. }
  17825. RPC_STATUS HTTP2ServerInChannel::ForwardFlowControlAck (
  17826. IN ULONG BytesReceivedForAck,
  17827. IN ULONG WindowForAck
  17828. )
  17829. /*++
  17830. Routine Description:
  17831. Forwards a flow control ack back to the in proxy
  17832. Arguments:
  17833. BytesReceivedForAck - the bytes received when the ACK was issued
  17834. WindowForAck - the free window when the ACK was issued.
  17835. Return Value:
  17836. RPC_S_OK or RPC_S_*
  17837. --*/
  17838. {
  17839. RPC_STATUS RpcStatus;
  17840. RpcStatus = ForwardFlowControlAckOnThisChannel(BytesReceivedForAck,
  17841. WindowForAck,
  17842. TRUE // NonChannelData
  17843. );
  17844. // we're sending non-channel data. This cannot lead to channel recycle
  17845. // indication
  17846. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  17847. return RpcStatus;
  17848. }
  17849. /*********************************************************************
  17850. HTTP2ServerOutChannel
  17851. *********************************************************************/
  17852. RPC_STATUS HTTP2ServerOutChannel::SendComplete (
  17853. IN RPC_STATUS EventStatus,
  17854. IN OUT HTTP2SendContext *SendContext
  17855. )
  17856. /*++
  17857. Routine Description:
  17858. Send complete notification
  17859. Arguments:
  17860. EventStatus - the status of the send
  17861. SendContext - send context
  17862. Return Value:
  17863. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  17864. --*/
  17865. {
  17866. if (SendContext->Flags & SendContextFlagAbandonedSend)
  17867. {
  17868. // abandoned send. Complete it silently and return back
  17869. ASSERT(SendContext->TrafficType == http2ttData);
  17870. RpcFreeBuffer(SendContext->u.BufferToFree);
  17871. FreeLastSendContext(SendContext);
  17872. return RPC_P_PACKET_CONSUMED;
  17873. }
  17874. return HTTP2Channel::SendComplete (EventStatus, SendContext);
  17875. }
  17876. RPC_STATUS HTTP2ServerOutChannel::SetKeepAliveTimeout (
  17877. IN BOOL TurnOn,
  17878. IN BOOL bProtectIO,
  17879. IN KEEPALIVE_TIMEOUT_UNITS Units,
  17880. IN OUT KEEPALIVE_TIMEOUT KATime,
  17881. IN ULONG KAInterval OPTIONAL
  17882. )
  17883. /*++
  17884. Routine Description:
  17885. Change the keep alive value on the channel
  17886. Arguments:
  17887. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  17888. are turned off.
  17889. bProtectIO - non-zero if IO needs to be protected against async close
  17890. of the connection.
  17891. Units - in what units is KATime
  17892. KATime - how much to wait before turning on keep alives
  17893. KAInterval - the interval between keep alives
  17894. Return Value:
  17895. RPC_S_OK or other RPC_S_* errors for error
  17896. --*/
  17897. {
  17898. // The server channel does not support this for Whistler
  17899. return RPC_S_CANNOT_SUPPORT;
  17900. }
  17901. RPC_STATUS HTTP2ServerOutChannel::LastPacketSentNotification (
  17902. IN HTTP2SendContext *LastSendContext
  17903. )
  17904. /*++
  17905. Routine Description:
  17906. When a lower channel wants to notify the top
  17907. channel that the last packet has been sent,
  17908. they call this function. Must be called from
  17909. an upcall/neutral context. Only flow control
  17910. senders support past packet notifications
  17911. Arguments:
  17912. LastSendContext - the context for the last send
  17913. Return Value:
  17914. The value to return to the runtime
  17915. --*/
  17916. {
  17917. HTTP2ServerVirtualConnection *VirtualConnection;
  17918. VirtualConnection = LockParentPointer();
  17919. // if the connection was already aborted, nothing to do
  17920. if (VirtualConnection == NULL)
  17921. return RPC_P_PACKET_CONSUMED;
  17922. // we know the parent will disconnect from us in their
  17923. // notification
  17924. VirtualConnection->LastPacketSentNotification(ChannelId,
  17925. LastSendContext);
  17926. UnlockParentPointer();
  17927. DrainUpcallsAndFreeParent();
  17928. return RPC_P_PACKET_CONSUMED;
  17929. }
  17930. HTTP2SendContext *HTTP2ServerOutChannel::GetLastSendContext (
  17931. void
  17932. )
  17933. /*++
  17934. Routine Description:
  17935. Gets (creates if necessary) a last send context.
  17936. Arguments:
  17937. Return Value:
  17938. The last context created or NULL if there is not enough memory
  17939. Notes:
  17940. Since each connection will submit one last send at a time, this
  17941. method can be single threaded.
  17942. --*/
  17943. {
  17944. if (CachedLastSendContextUsed == FALSE)
  17945. {
  17946. CachedLastSendContextUsed = TRUE;
  17947. return GetCachedLastSendContext();
  17948. }
  17949. else
  17950. {
  17951. return (new HTTP2SendContext);
  17952. }
  17953. }
  17954. /*********************************************************************
  17955. HTTP2ServerVirtualConnection
  17956. *********************************************************************/
  17957. void HTTP2ServerVirtualConnection::Abort (
  17958. void
  17959. )
  17960. /*++
  17961. Routine Description:
  17962. Aborts an HTTP connection and disconnects the channels.
  17963. Must only come from the runtime.
  17964. Arguments:
  17965. Return Value:
  17966. --*/
  17967. {
  17968. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_SERVER_VC, 0);
  17969. // abort the channels themselves
  17970. AbortChannels(RPC_P_CONNECTION_CLOSED);
  17971. // we got to the destructive phase of the abort
  17972. // guard against double aborts
  17973. if (Aborted.Increment() > 1)
  17974. return;
  17975. DisconnectChannels(FALSE, 0);
  17976. CancelAllTimeouts();
  17977. // call destructor without freeing memory
  17978. HTTP2ServerVirtualConnection::~HTTP2ServerVirtualConnection();
  17979. }
  17980. void HTTP2ServerVirtualConnection::Close (
  17981. IN BOOL DontFlush
  17982. )
  17983. /*++
  17984. Routine Description:
  17985. Closes an HTTP connection. Connection may have already been aborted.
  17986. Arguments:
  17987. DontFlush - non-zero if all buffers need to be flushed
  17988. before closing the connection. Zero otherwise.
  17989. Return Value:
  17990. --*/
  17991. {
  17992. CookieCollection *ServerCookieCollection = GetServerCookieCollection();
  17993. ServerCookieCollection->LockCollection();
  17994. ServerCookieCollection->RemoveElement(&EmbeddedConnectionCookie);
  17995. ServerCookieCollection->UnlockCollection();
  17996. HTTP2ServerVirtualConnection::Abort();
  17997. }
  17998. RPC_STATUS HTTP2ServerVirtualConnection::QueryClientAddress (
  17999. OUT RPC_CHAR **pNetworkAddress
  18000. )
  18001. /*++
  18002. Routine Description:
  18003. Returns the IP address of the client on a connection as a string.
  18004. This is a server side function. Assert on the client. Proxies don't
  18005. override that. Other virtual connections may override it.
  18006. Arguments:
  18007. NetworkAddress - Will contain string on success.
  18008. Return Value:
  18009. RPC_S_OK or other RPC_S_* errors for error
  18010. --*/
  18011. {
  18012. ULONG ClientAddressType;
  18013. if (ClientAddress.AddressType == catIPv4)
  18014. ClientAddressType = TCP;
  18015. else
  18016. ClientAddressType = TCP_IPv6;
  18017. return WS_ConvertClientAddress((const SOCKADDR *)&ClientAddress.u,
  18018. ClientAddressType,
  18019. pNetworkAddress
  18020. );
  18021. }
  18022. RPC_STATUS HTTP2ServerVirtualConnection::QueryLocalAddress (
  18023. IN OUT void *Buffer,
  18024. IN OUT unsigned long *BufferSize,
  18025. OUT unsigned long *AddressFormat
  18026. )
  18027. /*++
  18028. Routine Description:
  18029. Returns the local IP address of a connection.
  18030. This is a server side function. Assert on the client. Proxies don't
  18031. override that. Other virtual connections may override it.
  18032. Arguments:
  18033. Buffer - The buffer that will receive the output address
  18034. BufferSize - the size of the supplied Buffer on input. On output the
  18035. number of bytes written to the buffer. If the buffer is too small
  18036. to receive all the output data, ERROR_MORE_DATA is returned,
  18037. nothing is written to the buffer, and BufferSize is set to
  18038. the size of the buffer needed to return all the data.
  18039. AddressFormat - a constant indicating the format of the returned address.
  18040. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  18041. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  18042. Return Value:
  18043. RPC_S_OK or other RPC_S_* errors for error
  18044. --*/
  18045. {
  18046. HTTP2ServerInChannel *ServerInChannel;
  18047. HTTP2ChannelPointer *ChannelPtr;
  18048. RPC_STATUS RpcStatus;
  18049. ServerInChannel = LockDefaultInChannel(&ChannelPtr);
  18050. if (ServerInChannel == NULL)
  18051. return RPC_S_NO_CONTEXT_AVAILABLE;
  18052. RpcStatus = ServerInChannel->QueryLocalAddress(Buffer,
  18053. BufferSize,
  18054. AddressFormat
  18055. );
  18056. ChannelPtr->UnlockChannelPointer();
  18057. return RpcStatus;
  18058. }
  18059. RPC_STATUS HTTP2ServerVirtualConnection::QueryClientId(
  18060. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  18061. )
  18062. /*++
  18063. Routine Description:
  18064. For secure protocols (which TCP/IP is not) this is supposed to
  18065. give an ID which will be shared by all clients from the same
  18066. process. This prevents one user from grabbing another users
  18067. association group and using their context handles.
  18068. Since TCP/IP is not secure we return the IP address of the
  18069. client machine. This limits the attacks to other processes
  18070. running on the client machine which is better than nothing.
  18071. This is a server side function. Assert on the client. Proxies don't
  18072. override that. Other virtual connections may override it.
  18073. Arguments:
  18074. ClientProcess - Transport identification of the "client".
  18075. Return Value:
  18076. RPC_S_OK or other RPC_S_* errors for error
  18077. --*/
  18078. {
  18079. ClientProcess->SetHTTP2ClientIdentifier(AssociationGroupId.GetCookie(),
  18080. COOKIE_SIZE_IN_BYTES,
  18081. FALSE // fLocal
  18082. );
  18083. return RPC_S_OK;
  18084. }
  18085. void HTTP2ServerVirtualConnection::LastPacketSentNotification (
  18086. IN int ChannelId,
  18087. IN HTTP2SendContext *LastSendContext
  18088. )
  18089. /*++
  18090. Routine Description:
  18091. When a channel wants to notify the virtual connection
  18092. that the last packet has been sent, they call this function.
  18093. Must be called from an upcall/neutral context. Only flow control
  18094. senders generated past packet notifications
  18095. Arguments:
  18096. ChannelId - the channelfor which this notification is.
  18097. LastSendContext - the context for the last send
  18098. Return Value:
  18099. --*/
  18100. {
  18101. // this must not be on the default in channel
  18102. ASSERT(IsOutChannel(ChannelId));
  18103. ASSERT(!IsDefaultOutChannel(ChannelId));
  18104. // detach the channel that notified us. Since we're in upcall, we know
  18105. // we hold at least one reference
  18106. OutChannels[GetNonDefaultOutChannelSelector()].FreeChannelPointer(FALSE, // DrainUpCalls
  18107. FALSE, // CalledFromUpcallContext
  18108. FALSE, // Abort
  18109. RPC_S_OK // AbortStatus
  18110. );
  18111. }
  18112. RPC_STATUS HTTP2ServerVirtualConnection::RecycleChannel (
  18113. IN BOOL IsFromUpcall
  18114. )
  18115. /*++
  18116. Routine Description:
  18117. Initiates channel recycling on the server.
  18118. Arguments:
  18119. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  18120. Return Value:
  18121. RPC_S_OK of the recycling operation started successfully.
  18122. RPC_S_* error for errors.
  18123. --*/
  18124. {
  18125. HTTP2SendContext *D4_A1Context;
  18126. RPC_STATUS RpcStatus;
  18127. #if DBG
  18128. DbgPrint("RPCRT4: %d: Recycling OUT channel\n", GetCurrentProcessId());
  18129. #endif
  18130. // Send invitation to the client to start channel recycling
  18131. D4_A1Context = AllocateAndInitializeD4_A1 ();
  18132. if (D4_A1Context == NULL)
  18133. return RPC_S_OUT_OF_MEMORY;
  18134. OutChannelState.Mutex.Request();
  18135. // we shouldn't get recycle unless we're in an opened state
  18136. ASSERT(OutChannelState.State == http2svOpened);
  18137. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened_A4W, 1, 0);
  18138. OutChannelState.State = http2svOpened_A4W;
  18139. VerifyTimerNotSet (OutChannelTimer);
  18140. OutChannelState.Mutex.Clear();
  18141. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  18142. D4_A1Context
  18143. );
  18144. if (RpcStatus != RPC_S_OK)
  18145. FreeRTSPacket(D4_A1Context);
  18146. return RpcStatus;
  18147. }
  18148. RPC_STATUS HTTP2ServerVirtualConnection::SendComplete (
  18149. IN RPC_STATUS EventStatus,
  18150. IN OUT HTTP2SendContext *SendContext,
  18151. IN int ChannelId
  18152. )
  18153. /*++
  18154. Routine Description:
  18155. Called by lower layers to indicate send complete.
  18156. Arguments:
  18157. EventStatus - status of the operation
  18158. SendContext - the context for the send complete
  18159. ChannelId - which channel completed the operation
  18160. Return Value:
  18161. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  18162. be hidden from the runtime.
  18163. RPC_S_OK if the packet was processed successfully.
  18164. RPC_S_* error if there was an error while processing the
  18165. packet.
  18166. --*/
  18167. {
  18168. VerifyValidChannelId(ChannelId);
  18169. if (SendContext->TrafficType == http2ttRTS)
  18170. {
  18171. FreeSendContextAndPossiblyData(SendContext);
  18172. if (EventStatus != RPC_S_OK)
  18173. {
  18174. // any send failures on the server are cause for connection abortion
  18175. AbortChannels(EventStatus);
  18176. }
  18177. return RPC_P_PACKET_CONSUMED;
  18178. }
  18179. else
  18180. return EventStatus;
  18181. }
  18182. RPC_STATUS HTTP2ServerVirtualConnection::ReceiveComplete (
  18183. IN RPC_STATUS EventStatus,
  18184. IN BYTE *Buffer,
  18185. IN UINT BufferLength,
  18186. IN int ChannelId
  18187. )
  18188. /*++
  18189. Routine Description:
  18190. Called by lower layers to indicate receive complete
  18191. Arguments:
  18192. EventStatus - RPC_S_OK for success or RPC_S_* for error
  18193. Buffer - buffer received
  18194. BufferLength - length of buffer received
  18195. ChannelId - which channel completed the operation
  18196. Return Value:
  18197. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  18198. be hidden from the runtime.
  18199. RPC_S_OK if the packet was processed successfully.
  18200. RPC_S_* error if there was an error while processing the
  18201. packet.
  18202. --*/
  18203. {
  18204. HTTP2ServerOutChannel *OutChannel;
  18205. HTTP2ServerOutChannel *NewOutChannel;
  18206. HTTP2ServerInChannel *InChannel;
  18207. HTTP2ServerInChannel *InChannel2;
  18208. HTTP2ChannelPointer *ChannelPtr;
  18209. HTTP2ChannelPointer *NewChannelPtr;
  18210. HTTP2Cookie ChannelCookie;
  18211. RPC_STATUS RpcStatus;
  18212. HTTP2SendContext *EmptyRTS;
  18213. BOOL BufferFreed;
  18214. BOOL DataReceivePosted;
  18215. HTTP2ServerOpenedPacketType PacketType;
  18216. LIST_ENTRY NewBufferHead;
  18217. HTTP2SendContext *D4_A9Context;
  18218. HTTP2SendContext *D5_A5Context;
  18219. HTTP2SendContext *D5_B1OrB2Context;
  18220. HTTP2SendContext *D2_B2Context;
  18221. ULONG BytesReceivedForAck;
  18222. ULONG WindowForAck;
  18223. HTTP2ServerOutChannelOtherCmdPacketType OutChannelPacketType;
  18224. BOOL IsOtherCmd;
  18225. ULONG PingTrafficSent;
  18226. BOOL ChannelNotSet;
  18227. VerifyValidChannelId(ChannelId);
  18228. if (IsInChannel(ChannelId))
  18229. {
  18230. // in channel has an endpoint receiver. Delegate RTS and data failures to it
  18231. if (EventStatus != RPC_S_OK)
  18232. return EventStatus;
  18233. if (IsRTSPacket(Buffer))
  18234. {
  18235. RpcStatus = HTTPTransInfo->CreateThread();
  18236. if (RpcStatus != RPC_S_OK)
  18237. {
  18238. RpcFreeBuffer(Buffer);
  18239. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18240. return RPC_P_PACKET_CONSUMED;
  18241. }
  18242. BufferFreed = FALSE;
  18243. RpcStatus = CheckPacketForForwarding(Buffer,
  18244. BufferLength,
  18245. fdServer
  18246. );
  18247. if (RpcStatus == RPC_P_PACKET_NEEDS_FORWARDING)
  18248. {
  18249. // flow control acks have some weird routing. Handle
  18250. // them separately. First, test for other cmd, since it's
  18251. // cheaper
  18252. if (IsOtherCmdPacket(Buffer, BufferLength))
  18253. {
  18254. // we know this is a other cmd command. Now check for
  18255. // forwarded flow control ack
  18256. RpcStatus = ParseFlowControlAckPacketWithDestination (Buffer,
  18257. BufferLength,
  18258. fdOutProxy,
  18259. &BytesReceivedForAck,
  18260. &WindowForAck,
  18261. &ChannelCookie
  18262. );
  18263. if (RpcStatus == RPC_S_OK)
  18264. {
  18265. ChannelNotSet = FALSE;
  18266. // flow control ack. Route it based on which out channel has
  18267. // a matching cookie. It is possible that none has. That's ok -
  18268. // just drop the packet in these cases
  18269. if (OutChannelCookies[0].Compare(&ChannelCookie) == 0)
  18270. {
  18271. if (OutChannels[0].IsChannelSet())
  18272. {
  18273. RpcStatus = ForwardTrafficToChannel (
  18274. &OutChannels[0],
  18275. Buffer,
  18276. BufferLength
  18277. );
  18278. }
  18279. else
  18280. {
  18281. // see comment below where we check ChannelNotSet
  18282. ChannelNotSet = TRUE;
  18283. ASSERT(DefaultOutChannelSelector == 1);
  18284. }
  18285. }
  18286. else if (OutChannelCookies[1].Compare(&ChannelCookie) == 0)
  18287. {
  18288. if (OutChannels[1].IsChannelSet())
  18289. {
  18290. RpcStatus = ForwardTrafficToChannel (
  18291. &OutChannels[1],
  18292. Buffer,
  18293. BufferLength
  18294. );
  18295. }
  18296. else
  18297. {
  18298. // see comment below where we check ChannelNotSet
  18299. ChannelNotSet = TRUE;
  18300. ASSERT(DefaultOutChannelSelector == 0);
  18301. }
  18302. }
  18303. else
  18304. {
  18305. // fake failure - this will be handled below
  18306. RpcStatus = RPC_P_SEND_FAILED;
  18307. }
  18308. if (ChannelNotSet)
  18309. {
  18310. // we could have a match on a channel that does not exist
  18311. // if we are in D5 after D5/B1. The old channel still needs
  18312. // flow control, but the new channel cookie is current by
  18313. // now. In these cases the old channel cookie will be moved
  18314. // to the location of the cookie for the non-default channel
  18315. // Make sure this is the case. After that forward to the out proxy
  18316. // on the default channel. The out proxy will again compare cookies
  18317. // and will know which channel to forward the flow control ack to.
  18318. ASSERT(OutChannelState.State == http2svOpened);
  18319. RpcStatus = ForwardTrafficToDefaultChannel (
  18320. FALSE, // IsInChannel
  18321. Buffer,
  18322. BufferLength
  18323. );
  18324. }
  18325. // handle a recycling request if necessary
  18326. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  18327. TRUE // IsFromUpcall
  18328. );
  18329. // since forwarding may fail if channels are discarded, consume
  18330. // the packet and ignore the failure
  18331. if (RpcStatus != RPC_S_OK)
  18332. {
  18333. RpcFreeBuffer(Buffer);
  18334. RpcStatus = RPC_S_OK;
  18335. }
  18336. }
  18337. else
  18338. {
  18339. // not a forwarded flow control ack after all. Just
  18340. // forward it using normal methods
  18341. RpcStatus = ForwardTrafficToDefaultChannel(
  18342. FALSE, // IsInChannel
  18343. Buffer,
  18344. BufferLength
  18345. );
  18346. }
  18347. }
  18348. else
  18349. {
  18350. RpcStatus = ForwardTrafficToDefaultChannel(
  18351. FALSE, // IsInChannel
  18352. Buffer,
  18353. BufferLength
  18354. );
  18355. }
  18356. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  18357. TRUE // IsFromUpcall
  18358. );
  18359. if (RpcStatus != RPC_S_OK)
  18360. {
  18361. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18362. RpcFreeBuffer(Buffer);
  18363. return RPC_P_PACKET_CONSUMED;
  18364. }
  18365. // we no longer own the buffer
  18366. BufferFreed = TRUE;
  18367. }
  18368. else if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  18369. {
  18370. // RTS packet is for us but is garbled
  18371. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18372. RpcFreeBuffer(Buffer);
  18373. return RPC_P_PACKET_CONSUMED;
  18374. }
  18375. else
  18376. {
  18377. RpcStatus = GetServerOpenedPacketType (Buffer,
  18378. BufferLength,
  18379. &PacketType
  18380. );
  18381. if (RpcStatus != RPC_S_OK)
  18382. {
  18383. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18384. RpcFreeBuffer(Buffer);
  18385. return RPC_P_PACKET_CONSUMED;
  18386. }
  18387. if ((PacketType == http2soptD4_A8orD5_A8) || (PacketType == http2soptD2_A6orD3_A2))
  18388. {
  18389. InChannelState.Mutex.Request();
  18390. if (PacketType == http2soptD4_A8orD5_A8)
  18391. {
  18392. // determine whether it is D4/A8 or D5/A8 based on the state
  18393. // we are in
  18394. if (OutChannelState.State == http2svOpened_A8W)
  18395. PacketType = http2soptD4_A8;
  18396. else if (OutChannelState.State == http2svOpened_D5A8W)
  18397. PacketType = http2soptD5_A8;
  18398. else
  18399. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18400. }
  18401. else
  18402. {
  18403. // determine whether it is D2/A6 or D3/A2 based on the state
  18404. // we are in
  18405. if (InChannelState.State == http2svOpened_A6W)
  18406. PacketType = http2soptD2_A6;
  18407. else if (OutChannelState.State == http2svOpened)
  18408. PacketType = http2soptD3_A2;
  18409. else
  18410. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18411. }
  18412. InChannelState.Mutex.Clear();
  18413. }
  18414. if (RpcStatus != RPC_S_OK)
  18415. {
  18416. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18417. RpcFreeBuffer(Buffer);
  18418. return RPC_P_PACKET_CONSUMED;
  18419. }
  18420. switch (PacketType)
  18421. {
  18422. case http2soptD2_A6:
  18423. // this would better be D2/A6
  18424. RpcStatus = ParseAndFreeD2_A6 (Buffer,
  18425. BufferLength,
  18426. &ChannelCookie
  18427. );
  18428. BufferFreed = TRUE;
  18429. // we got D2/A6. Cancel the timeout we setup with D2/A2
  18430. CancelTimeout(InChannelTimer);
  18431. if (RpcStatus != RPC_S_OK)
  18432. {
  18433. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18434. return RPC_P_PACKET_CONSUMED;
  18435. }
  18436. if (InChannelCookies[GetNonDefaultInChannelSelector()].Compare(&ChannelCookie))
  18437. {
  18438. // cookies don't match - nuke the channel
  18439. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18440. return RPC_P_PACKET_CONSUMED;
  18441. }
  18442. InChannelState.Mutex.Request();
  18443. // we haven't posted a receive yet - there is no
  18444. // way the state of the channel will change
  18445. ASSERT(InChannelState.State == http2svOpened_A6W);
  18446. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened_B1W, 1, 0);
  18447. InChannelState.State = http2svOpened_B1W;
  18448. InChannelState.Mutex.Clear();
  18449. break;
  18450. case http2soptD3_A2:
  18451. if (IsDefaultInChannel(ChannelId) == FALSE)
  18452. {
  18453. ASSERT(0);
  18454. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18455. RpcFreeBuffer(Buffer);
  18456. return RPC_P_PACKET_CONSUMED;
  18457. }
  18458. RpcStatus = ParseAndFreeD3_A2 (Buffer,
  18459. BufferLength,
  18460. &ChannelCookie
  18461. );
  18462. BufferFreed = TRUE;
  18463. if (RpcStatus != RPC_S_OK)
  18464. {
  18465. AbortChannels(RpcStatus);
  18466. return RPC_P_PACKET_CONSUMED;
  18467. }
  18468. // update the passed in cookie
  18469. InChannelCookies[DefaultInChannelSelector].SetCookie(ChannelCookie.GetCookie());
  18470. // pass D3/A3 back
  18471. EmptyRTS = AllocateAndInitializeEmptyRTSWithDestination (fdClient);
  18472. if (EmptyRTS == NULL)
  18473. {
  18474. AbortChannels(RpcStatus);
  18475. return RPC_P_PACKET_CONSUMED;
  18476. }
  18477. RpcStatus = SendTrafficOnDefaultChannel (FALSE, // IsInChannel
  18478. EmptyRTS
  18479. );
  18480. break;
  18481. case http2soptD2_B1:
  18482. InChannelState.Mutex.Request();
  18483. if (InChannelState.State != http2svOpened_B1W)
  18484. {
  18485. InChannelState.Mutex.Clear();
  18486. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18487. RpcFreeBuffer(Buffer);
  18488. return RPC_P_PACKET_CONSUMED;
  18489. }
  18490. InChannelState.Mutex.Clear();
  18491. RpcStatus = ParseAndFreeEmptyRTS(Buffer,
  18492. BufferLength);
  18493. // we no longer own the buffer
  18494. BufferFreed = TRUE;
  18495. if (RpcStatus != RPC_S_OK)
  18496. {
  18497. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18498. return RPC_P_PACKET_CONSUMED;
  18499. }
  18500. // we're done with this channel. We want to switch
  18501. // channels and destroy
  18502. // and detach the channel.
  18503. SwitchDefaultInChannelSelector();
  18504. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18505. InChannel = (HTTP2ServerInChannel *)ChannelPtr->LockChannelPointer();
  18506. if (InChannel == NULL)
  18507. {
  18508. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18509. return RPC_P_PACKET_CONSUMED;
  18510. }
  18511. InChannel2 = LockDefaultInChannel(&NewChannelPtr);
  18512. if (InChannel2 == NULL)
  18513. {
  18514. ChannelPtr->UnlockChannelPointer();
  18515. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18516. return RPC_P_PACKET_CONSUMED;
  18517. }
  18518. DataReceivePosted = InChannel->IsDataReceivePosted();
  18519. RpcStatus = InChannel->TransferReceiveStateToNewChannel(InChannel2);
  18520. NewChannelPtr->UnlockChannelPointer();
  18521. ChannelPtr->UnlockChannelPointer();
  18522. if (RpcStatus != RPC_S_OK)
  18523. {
  18524. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18525. return RPC_P_PACKET_CONSUMED;
  18526. }
  18527. D2_B2Context = AllocateAndInitializeD2_B2 (HTTP2ServerReceiveWindow);
  18528. if (D2_B2Context == NULL)
  18529. {
  18530. AbortChannels(RPC_S_OUT_OF_MEMORY);
  18531. return RPC_P_PACKET_CONSUMED;
  18532. }
  18533. // now that we have transferred the settings, we can open
  18534. // the pipeline from the new in proxy
  18535. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  18536. D2_B2Context
  18537. );
  18538. if (RpcStatus != RPC_S_OK)
  18539. {
  18540. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18541. FreeRTSPacket(D2_B2Context);
  18542. return RPC_P_PACKET_CONSUMED;
  18543. }
  18544. // detach, abort and free lifetime reference
  18545. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  18546. TRUE, // CalledFromUpcallContext
  18547. TRUE, // Abort
  18548. RPC_P_CONNECTION_SHUTDOWN
  18549. );
  18550. InChannelState.Mutex.Request();
  18551. // we haven't posted a receive yet - there is no
  18552. // way the state of the channel will change
  18553. ASSERT(InChannelState.State == http2svOpened_B1W);
  18554. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  18555. InChannelState.State = http2svOpened;
  18556. InChannelState.Mutex.Clear();
  18557. if (DataReceivePosted)
  18558. {
  18559. RpcStatus = PostReceiveOnDefaultChannel (
  18560. TRUE, // IsInChannel
  18561. http2ttData
  18562. );
  18563. if (RpcStatus != RPC_S_OK)
  18564. {
  18565. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18566. }
  18567. }
  18568. return RPC_P_PACKET_CONSUMED;
  18569. break;
  18570. case http2soptD4_A8:
  18571. // verify the new cookie against the old, and execute
  18572. // the detachment of the old channel after sending D4_A9
  18573. InChannelState.Mutex.Request();
  18574. if (OutChannelState.State != http2svOpened_A8W)
  18575. {
  18576. InChannelState.Mutex.Clear();
  18577. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18578. break;
  18579. }
  18580. // move back to opened state
  18581. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  18582. OutChannelState.State = http2svOpened;
  18583. InChannelState.Mutex.Clear();
  18584. RpcStatus = ParseAndFreeD4_A8 (Buffer,
  18585. BufferLength,
  18586. fdServer,
  18587. &ChannelCookie
  18588. );
  18589. BufferFreed = TRUE;
  18590. // we got D4/A8. Cancel the timeout we setup with D4/A4
  18591. CancelTimeout(OutChannelTimer);
  18592. if (RpcStatus != RPC_S_OK)
  18593. break;
  18594. if (OutChannelCookies[GetNonDefaultOutChannelSelector()].Compare(&ChannelCookie))
  18595. {
  18596. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18597. break;
  18598. }
  18599. // lock the old channel
  18600. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  18601. if (OutChannel == NULL)
  18602. {
  18603. RpcStatus = RPC_P_CONNECTION_CLOSED;
  18604. break;
  18605. }
  18606. // switch channels (new channel is still plugged)
  18607. SwitchDefaultOutChannelSelector();
  18608. // wait for all submits to get out of old channel
  18609. OutChannel->DrainPendingSubmissions();
  18610. // leave 1 for our lock
  18611. ChannelPtr->DrainPendingLocks(1);
  18612. // lock new channel (by now it is default)
  18613. NewOutChannel = LockDefaultOutChannel(&NewChannelPtr);
  18614. if (NewOutChannel == NULL)
  18615. {
  18616. ChannelPtr->UnlockChannelPointer();
  18617. RpcStatus = RPC_P_CONNECTION_CLOSED;
  18618. break;
  18619. }
  18620. // if flow control sender was queuing, grab all its buffers as well.
  18621. // Note that the flow control sender is higher in the stack and must
  18622. // be done first (to preserve packet ordering)
  18623. RpcpInitializeListHead(&NewBufferHead);
  18624. OutChannel->GetFlowControlSenderBufferQueue(&NewBufferHead);
  18625. AddBufferQueueToChannel(&NewBufferHead, NewOutChannel);
  18626. // GetChannelOriginatorBufferQueue must be called in submission
  18627. // context only. Get there
  18628. RpcStatus = OutChannel->BeginSimpleSubmitAsync();
  18629. if (RpcStatus != RPC_S_OK)
  18630. {
  18631. NewChannelPtr->UnlockChannelPointer();
  18632. ChannelPtr->UnlockChannelPointer();
  18633. break;
  18634. }
  18635. // if old channel was queuing, grab all its buffers. Since it is
  18636. // below the flow control sender, we must do it second to make sure
  18637. // they are before the flow control sender's buffers
  18638. RpcpInitializeListHead(&NewBufferHead);
  18639. OutChannel->GetChannelOriginatorBufferQueue(&NewBufferHead);
  18640. OutChannel->FinishSubmitAsync();
  18641. AddBufferQueueToChannel(&NewBufferHead, NewOutChannel);
  18642. // register the last packet to send with the old channel
  18643. D4_A9Context = AllocateAndInitializeD4_A9 ();
  18644. if (D4_A9Context == NULL)
  18645. {
  18646. ChannelPtr->UnlockChannelPointer();
  18647. NewChannelPtr->UnlockChannelPointer();
  18648. RpcStatus = RPC_S_OUT_OF_MEMORY;
  18649. break;
  18650. }
  18651. RpcStatus = OutChannel->Send(D4_A9Context);
  18652. if (RpcStatus != RPC_S_OK)
  18653. {
  18654. ChannelPtr->UnlockChannelPointer();
  18655. NewChannelPtr->UnlockChannelPointer();
  18656. FreeRTSPacket(D4_A9Context);
  18657. break;
  18658. }
  18659. // D4_A9 was sent. We must switch the
  18660. // default loopback and detach the channel.
  18661. // Note that we don't abort the channel - we
  18662. // just release the lifetime reference
  18663. // When the proxy closes the connection, then
  18664. // we will abort
  18665. ChannelPtr->UnlockChannelPointer();
  18666. RpcStatus = NewOutChannel->Unplug();
  18667. NewChannelPtr->UnlockChannelPointer();
  18668. if (RpcStatus != RPC_S_OK)
  18669. break;
  18670. RpcStatus = RPC_P_PACKET_CONSUMED;
  18671. break;
  18672. case http2soptD5_A8:
  18673. // verify the new cookie against the old, and execute
  18674. // the detachment of the old channel after sending D4_A9
  18675. InChannelState.Mutex.Request();
  18676. if (OutChannelState.State != http2svOpened_D5A8W)
  18677. {
  18678. InChannelState.Mutex.Clear();
  18679. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18680. break;
  18681. }
  18682. RpcStatus = ParseAndFreeD5_A8 (Buffer,
  18683. BufferLength,
  18684. fdServer,
  18685. &ChannelCookie
  18686. );
  18687. BufferFreed = TRUE;
  18688. CancelTimeout(OutChannelTimer);
  18689. if (RpcStatus != RPC_S_OK)
  18690. {
  18691. InChannelState.Mutex.Clear();
  18692. break;
  18693. }
  18694. // we use the non-default out channel cookie simply as temporary storage
  18695. // b/n D5/A4 and D5/A8
  18696. if (OutChannelCookies[GetNonDefaultOutChannelSelector()].Compare(&ChannelCookie))
  18697. {
  18698. // the new channel is fake. Tell the proxy about it, and it will ditch it
  18699. D5_B1OrB2Context = AllocateAndInitializeD5_B1orB2 (FALSE);
  18700. if (D5_B1OrB2Context == NULL)
  18701. {
  18702. InChannelState.Mutex.Clear();
  18703. RpcStatus = RPC_S_OUT_OF_MEMORY;
  18704. break;
  18705. }
  18706. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  18707. D5_B1OrB2Context);
  18708. if (RpcStatus != RPC_S_OK)
  18709. {
  18710. InChannelState.Mutex.Clear();
  18711. FreeRTSPacket(D5_B1OrB2Context);
  18712. break;
  18713. }
  18714. // move back to opened state
  18715. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  18716. OutChannelState.State = http2svOpened;
  18717. InChannelState.Mutex.Clear();
  18718. break;
  18719. }
  18720. // the cookie matches. Move the new channel cookie from temporary to permanent
  18721. // storage and move the old channel cookie to temp storage
  18722. // move old cookie to temp storage
  18723. ChannelCookie.SetCookie(
  18724. OutChannelCookies[DefaultOutChannelSelector].GetCookie());
  18725. // move new cookie from class temp storage to permanent storage
  18726. OutChannelCookies[DefaultOutChannelSelector].SetCookie (
  18727. OutChannelCookies[GetNonDefaultOutChannelSelector()].GetCookie());
  18728. // move the old cookie from local temporary storage to class temporary storage
  18729. OutChannelCookies[GetNonDefaultOutChannelSelector()].SetCookie (
  18730. ChannelCookie.GetCookie());
  18731. // move back to opened state
  18732. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  18733. OutChannelState.State = http2svOpened;
  18734. InChannelState.Mutex.Clear();
  18735. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  18736. if (OutChannel == NULL)
  18737. {
  18738. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  18739. break;
  18740. }
  18741. OutChannel->PlugDataOriginatorChannel();
  18742. // Wait for everybody that was in to get out. This way we know
  18743. // the channel was plugged.
  18744. // we know that this will complete because eventually the runtime
  18745. // will flow control itself if there is no lull in sent traffic
  18746. OutChannel->DrainPendingSubmissions();
  18747. D5_B1OrB2Context = AllocateAndInitializeD5_B1orB2 (TRUE);
  18748. if (D5_B1OrB2Context == NULL)
  18749. {
  18750. ChannelPtr->UnlockChannelPointer();
  18751. RpcStatus = RPC_S_OUT_OF_MEMORY;
  18752. break;
  18753. }
  18754. RpcStatus = OutChannel->Send(D5_B1OrB2Context);
  18755. if (RpcStatus != RPC_S_OK)
  18756. {
  18757. ChannelPtr->UnlockChannelPointer();
  18758. FreeRTSPacket(D5_B1OrB2Context);
  18759. break;
  18760. }
  18761. RpcStatus = OutChannel->RestartDataOriginatorChannel();
  18762. ChannelPtr->UnlockChannelPointer();
  18763. // fall through the error code
  18764. break;
  18765. default:
  18766. ASSERT(0);
  18767. break;
  18768. }
  18769. }
  18770. RpcStatus = PostReceiveOnDefaultChannel(
  18771. TRUE, // IsInChannel
  18772. http2ttRTS
  18773. );
  18774. if (RpcStatus != RPC_S_OK)
  18775. AbortChannels(RPC_P_CONNECTION_CLOSED);
  18776. if (BufferFreed == FALSE)
  18777. RpcFreeBuffer(Buffer);
  18778. return RPC_P_PACKET_CONSUMED;
  18779. }
  18780. else
  18781. {
  18782. return EventStatus;
  18783. }
  18784. }
  18785. else
  18786. {
  18787. if (EventStatus != RPC_S_OK)
  18788. {
  18789. if (IsDefaultOutChannel(ChannelId) == FALSE)
  18790. {
  18791. InChannelState.Mutex.Request();
  18792. if (OutChannelState.State == http2svOpened)
  18793. {
  18794. // close on the non-default channel in open
  18795. // state is not an error. Just discard the channel
  18796. InChannelState.Mutex.Clear();
  18797. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18798. ChannelPtr->FreeChannelPointer(
  18799. TRUE, // DrainUpcalls
  18800. TRUE, // CalledFromUpcallContext
  18801. TRUE, // Abort
  18802. RPC_P_CONNECTION_SHUTDOWN
  18803. );
  18804. RpcStatus = RPC_P_PACKET_CONSUMED;
  18805. BufferFreed = TRUE;
  18806. return RpcStatus;
  18807. }
  18808. else
  18809. InChannelState.Mutex.Clear();
  18810. }
  18811. else if (InChannelState.State == http2svB2W)
  18812. {
  18813. // if this is a half open connection, treat
  18814. // this as data receive and indicate it to the
  18815. // runtime
  18816. AbortChannels(EventStatus);
  18817. // if we are still in this state, return error to the
  18818. // runtime. Else, somebody else joined and we can ignore
  18819. // this error
  18820. if (InChannelState.State == http2svB2W)
  18821. {
  18822. return EventStatus;
  18823. }
  18824. else
  18825. {
  18826. // consume the receive
  18827. return RPC_P_PACKET_CONSUMED;
  18828. }
  18829. }
  18830. AbortChannels(EventStatus);
  18831. // we expect only RTS traffic on this channel. Nobody would post
  18832. // a data receive on this channel. Consume the receive
  18833. return RPC_P_PACKET_CONSUMED;
  18834. }
  18835. if (IsRTSPacket(Buffer))
  18836. {
  18837. RpcStatus = HTTPTransInfo->CreateThread();
  18838. if (RpcStatus != RPC_S_OK)
  18839. {
  18840. RpcFreeBuffer(Buffer);
  18841. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18842. return RPC_P_PACKET_CONSUMED;
  18843. }
  18844. IsOtherCmd = IsOtherCmdPacket(Buffer,
  18845. BufferLength
  18846. );
  18847. RpcStatus = GetServerOutChannelOtherCmdPacketType (
  18848. Buffer,
  18849. BufferLength,
  18850. &OutChannelPacketType
  18851. );
  18852. if (RpcStatus != RPC_S_OK)
  18853. {
  18854. RpcFreeBuffer(Buffer);
  18855. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18856. return RPC_P_PACKET_CONSUMED;
  18857. }
  18858. if (IsOtherCmd && (OutChannelPacketType == http2sococptFlowControl))
  18859. {
  18860. RpcStatus = ParseAndFreeFlowControlAckPacket (Buffer,
  18861. BufferLength,
  18862. &BytesReceivedForAck,
  18863. &WindowForAck,
  18864. &ChannelCookie
  18865. );
  18866. if (RpcStatus == RPC_S_OK)
  18867. {
  18868. // notify the flow control sender
  18869. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18870. OutChannel = (HTTP2ServerOutChannel *)ChannelPtr->LockChannelPointer();
  18871. // forward acks only on default channels. Non-default channels
  18872. // will have all their buffers transfered to the new channel in the
  18873. // immediate future. If we forward to them, we can cause nasty
  18874. // race conditions as another thread tries to get channels out of them
  18875. if (IsDefaultOutChannel(ChannelId))
  18876. {
  18877. if (OutChannel == NULL)
  18878. {
  18879. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  18880. return RPC_P_PACKET_CONSUMED;
  18881. }
  18882. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  18883. WindowForAck
  18884. );
  18885. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  18886. TRUE // IsFromUpcall
  18887. );
  18888. }
  18889. ChannelPtr->UnlockChannelPointer();
  18890. if (RpcStatus == RPC_S_OK)
  18891. {
  18892. // post another receive
  18893. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  18894. http2ttRaw
  18895. );
  18896. }
  18897. }
  18898. if (RpcStatus != RPC_S_OK)
  18899. {
  18900. AbortChannels(RpcStatus);
  18901. }
  18902. }
  18903. else if (IsOtherCmd && (OutChannelPacketType == http2sococptPingTrafficSentNotify))
  18904. {
  18905. RpcStatus = ParseAndFreePingTrafficSentNotifyPacket (Buffer,
  18906. BufferLength,
  18907. &PingTrafficSent
  18908. );
  18909. if (RpcStatus == RPC_S_OK)
  18910. {
  18911. // notify the channel data originator
  18912. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18913. OutChannel = (HTTP2ServerOutChannel *)ChannelPtr->LockChannelPointer();
  18914. if (OutChannel == NULL)
  18915. {
  18916. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  18917. return RPC_P_PACKET_CONSUMED;
  18918. }
  18919. // prevent bogus values from the proxy. We allow no more than
  18920. // approximately MaxBytesSentByProxy bytes per BytesSentByProxyTimeInterval.
  18921. // The exact calculation doesn't matter. This requirement is so much below
  18922. // the bar necessary to attack the server, that anything close to it makes
  18923. // us safe
  18924. if (BytesSentByProxyTimeIntervalStart == 0)
  18925. BytesSentByProxyTimeIntervalStart = NtGetTickCount();
  18926. else
  18927. {
  18928. if (NtGetTickCount() - BytesSentByProxyTimeIntervalStart > BytesSentByProxyTimeInterval)
  18929. {
  18930. // start a new interval
  18931. BytesSentByProxyTimeIntervalStart = NtGetTickCount();
  18932. BytesSentByProxyForInterval = PingTrafficSent;
  18933. }
  18934. else
  18935. {
  18936. BytesSentByProxyForInterval += PingTrafficSent;
  18937. }
  18938. if (BytesSentByProxyForInterval > MaxBytesSentByProxy)
  18939. {
  18940. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18941. return RPC_P_PACKET_CONSUMED;
  18942. }
  18943. }
  18944. RpcStatus = OutChannel->NotifyDataOriginatorForTrafficSent (PingTrafficSent);
  18945. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  18946. TRUE // IsFromUpcall
  18947. );
  18948. ChannelPtr->UnlockChannelPointer();
  18949. if (RpcStatus == RPC_S_OK)
  18950. {
  18951. // post another receive
  18952. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  18953. http2ttRaw
  18954. );
  18955. }
  18956. }
  18957. if (RpcStatus != RPC_S_OK)
  18958. {
  18959. AbortChannels(RpcStatus);
  18960. }
  18961. }
  18962. else
  18963. {
  18964. // the only packet we expect here is D5/A4
  18965. // we must be in Opened_A4W state for it
  18966. InChannelState.Mutex.Request();
  18967. if (OutChannelState.State != http2svOpened_A4W)
  18968. {
  18969. InChannelState.Mutex.Clear();
  18970. RpcFreeBuffer(Buffer);
  18971. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18972. return RPC_P_PACKET_CONSUMED;
  18973. }
  18974. RpcStatus = ParseAndFreeD5_A4 (Buffer,
  18975. BufferLength,
  18976. &OutChannelCookies[GetNonDefaultOutChannelSelector()]
  18977. );
  18978. if (RpcStatus != RPC_S_OK)
  18979. {
  18980. AbortChannels(RPC_S_PROTOCOL_ERROR);
  18981. InChannelState.Mutex.Clear();
  18982. return RPC_P_PACKET_CONSUMED;
  18983. }
  18984. // move to Opened_A8W state
  18985. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened_D5A8W, 1, 0);
  18986. OutChannelState.State = http2svOpened_D5A8W;
  18987. InChannelState.Mutex.Clear();
  18988. RpcStatus = SetTimeout(DefaultNoResponseTimeout, OutChannelTimer);
  18989. if (RpcStatus != RPC_S_OK)
  18990. {
  18991. AbortChannels(RpcStatus);
  18992. return RPC_P_PACKET_CONSUMED;
  18993. }
  18994. // send out D5/A5
  18995. D5_A5Context = AllocateAndInitializeD5_A5 (fdClient);
  18996. if (D5_A5Context == NULL)
  18997. {
  18998. AbortChannels(RPC_S_OUT_OF_MEMORY);
  18999. return RPC_P_PACKET_CONSUMED;
  19000. }
  19001. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  19002. D5_A5Context
  19003. );
  19004. if (RpcStatus != RPC_S_OK)
  19005. {
  19006. AbortChannels(RPC_S_OUT_OF_MEMORY);
  19007. FreeRTSPacket(D5_A5Context);
  19008. return RPC_P_PACKET_CONSUMED;
  19009. }
  19010. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  19011. http2ttRaw
  19012. );
  19013. if (RpcStatus != RPC_S_OK)
  19014. AbortChannels(RpcStatus);
  19015. }
  19016. return RPC_P_PACKET_CONSUMED;
  19017. }
  19018. else
  19019. return EventStatus;
  19020. }
  19021. }
  19022. RPC_STATUS HTTP2ServerVirtualConnection::SyncSend (
  19023. IN ULONG BufferLength,
  19024. IN BYTE *Buffer,
  19025. IN BOOL fDisableShutdownCheck,
  19026. IN BOOL fDisableCancelCheck,
  19027. IN ULONG Timeout
  19028. )
  19029. /*++
  19030. Routine Description:
  19031. Does a sync send on a server HTTP connection.
  19032. Arguments:
  19033. BufferLength - the length of the data to send.
  19034. Buffer - the data to send.
  19035. fDisableShutdownCheck - ignored
  19036. fDisableCancelCheck - runtime indicates no cancel
  19037. will be attempted on this send. Can be used
  19038. as optimization hint by the transport
  19039. Timeout - send timeout (call timeout)
  19040. Return Value:
  19041. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  19042. --*/
  19043. {
  19044. RPC_STATUS RpcStatus;
  19045. RPC_STATUS RpcStatus2;
  19046. HTTP2SendContext *SendContext;
  19047. HTTP2ServerOutChannel *Channel;
  19048. HTTP2ChannelPointer *ChannelPtr;
  19049. OutChannelState.Mutex.Request();
  19050. if (OutChannelState.State == http2svOpened)
  19051. {
  19052. VerifyTimerNotSet(OutChannelTimer);
  19053. }
  19054. OutChannelState.Mutex.Clear();
  19055. // if the caller did not set a last buffer to free, we can't abandon the send
  19056. // because we can't cleanup. Wait for the send to complete.
  19057. if (IsLastBufferToFreeSet() == FALSE)
  19058. {
  19059. return HTTP2VirtualConnection::SyncSend (BufferLength,
  19060. Buffer,
  19061. fDisableShutdownCheck,
  19062. fDisableCancelCheck,
  19063. Timeout
  19064. );
  19065. }
  19066. // we will complete this as an async send behind the covers
  19067. // and we will fake success unless the submission itself
  19068. // fails
  19069. Channel = (HTTP2ServerOutChannel *)LockDefaultSendChannel (&ChannelPtr);
  19070. if (Channel == NULL)
  19071. {
  19072. return RPC_P_CONNECTION_CLOSED;
  19073. }
  19074. SendContext = Channel->GetLastSendContext();
  19075. if (SendContext == NULL)
  19076. {
  19077. ChannelPtr->UnlockChannelPointer();
  19078. return RPC_S_OUT_OF_MEMORY;
  19079. }
  19080. SendContext->u.BufferToFree = GetAndResetLastBufferToFree();
  19081. SendContext->SetListEntryUnused();
  19082. SendContext->maxWriteBuffer = BufferLength;
  19083. SendContext->pWriteBuffer = Buffer;
  19084. // SendContext->Write.pAsyncObject = NULL; // this will be initialized in the bottom layer
  19085. SendContext->Write.ol.Internal = STATUS_PENDING;
  19086. SendContext->TrafficType = http2ttData;
  19087. SendContext->Write.ol.OffsetHigh = 0;
  19088. SendContext->Flags = SendContextFlagAbandonedSend;
  19089. SendContext->UserData = 0;
  19090. RpcStatus = Channel->Send(SendContext);
  19091. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  19092. {
  19093. // synchronous failure - cleanup
  19094. RpcFreeBuffer(SendContext->u.BufferToFree);
  19095. Channel->FreeLastSendContext(SendContext);
  19096. }
  19097. ChannelPtr->UnlockChannelPointer();
  19098. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  19099. {
  19100. // make sure there is a thread to pick up the recycling events
  19101. RpcStatus = HTTPTransInfo->CreateThread();
  19102. if (RpcStatus != RPC_S_OK)
  19103. {
  19104. VALIDATE(RpcStatus)
  19105. {
  19106. RPC_S_OK,
  19107. RPC_S_OUT_OF_MEMORY,
  19108. RPC_S_OUT_OF_RESOURCES,
  19109. RPC_P_SEND_FAILED,
  19110. RPC_S_CALL_CANCELLED,
  19111. RPC_P_RECEIVE_COMPLETE,
  19112. RPC_P_TIMEOUT
  19113. } END_VALIDATE;
  19114. return RpcStatus;
  19115. }
  19116. // get the ball rolling with the recycle
  19117. RpcStatus = RecycleChannel(
  19118. FALSE // IsFromUpcall
  19119. );
  19120. }
  19121. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  19122. || (RpcStatus == RPC_P_RECEIVE_FAILED)
  19123. || (RpcStatus == RPC_P_CONNECTION_CLOSED) )
  19124. RpcStatus = RPC_P_SEND_FAILED;
  19125. VALIDATE(RpcStatus)
  19126. {
  19127. RPC_S_OK,
  19128. RPC_S_OUT_OF_MEMORY,
  19129. RPC_S_OUT_OF_RESOURCES,
  19130. RPC_P_SEND_FAILED,
  19131. RPC_S_CALL_CANCELLED,
  19132. RPC_P_RECEIVE_COMPLETE,
  19133. RPC_P_TIMEOUT
  19134. } END_VALIDATE;
  19135. return RpcStatus;
  19136. }
  19137. RPC_STATUS HTTP2ServerVirtualConnection::InitializeServerConnection (
  19138. IN BYTE *Packet,
  19139. IN ULONG PacketLength,
  19140. IN WS_HTTP2_INITIAL_CONNECTION *Connection,
  19141. OUT HTTP2ServerVirtualConnection **ServerVirtualConnection,
  19142. OUT BOOL *VirtualConnectionCreated
  19143. )
  19144. /*++
  19145. Routine Description:
  19146. Initializes a server connection. Based on the content of the
  19147. packet (i.e. D1/A2 or D1/B2), it will either initialize the
  19148. out channel or the in channel respectively, and if it is
  19149. the first leg of the connection establishment, establish the
  19150. virtual connection itself and insert it into the cookie table
  19151. Note: This function must initialize the type member and migrate the
  19152. WS_HTTP2_INITIAL_CONNECTION after morphing it into
  19153. WS_HTTP2_CONNECTION. The VirtualConnectionCreated parameter indicates
  19154. whether this was done.
  19155. Arguments:
  19156. Packet - received packet. Guaranteed to be present until PacketLength.
  19157. On second leg, this function must not free the buffer. Ownership
  19158. of the buffer remains with the caller.
  19159. PacketLength - the lenght of the received packet.
  19160. Connection - the received connection. It must be migrated
  19161. and morphed into WS_HTTP2_CONNECTION on success. If the virtual
  19162. connection was already created, then returning failure without
  19163. un-migrating is fine. Cleanup paths will check and recognize this
  19164. as HTTP2ServerVirtualConnection.
  19165. ServerVirtualConnection - on successful return, the created server virtual
  19166. connection
  19167. VirtualConnectionCreated - if non-zero, the WS_HTTP2_INITIAL_CONNECTION
  19168. was morphed into virtual connection. Else, the WS_HTTP2_INITIAL_CONNECTION
  19169. is still around. Must be set on success and failure.
  19170. Return Value:
  19171. RPC_S_OK or RPC_S_* for error. If we return RPC_S_OK, the packet will be
  19172. consumed by caller. If we return anything else, it won't be.
  19173. --*/
  19174. {
  19175. RPC_STATUS RpcStatus;
  19176. RPC_STATUS RpcStatus2;
  19177. HTTP2FirstServerPacketType PacketType;
  19178. WS_HTTP2_INITIAL_CONNECTION *OriginalConnection = Connection;
  19179. HTTP2ServerInChannel *InChannel = NULL;
  19180. HTTP2ServerOutChannel *OutChannel = NULL;
  19181. HTTP2ServerCookie ServerCookie;
  19182. HTTP2Cookie ChannelCookie;
  19183. HTTP2Cookie NewChannelCookie;
  19184. ULONG OutProxyReceiveWindow;
  19185. ULONG ProtocolVersion;
  19186. ULONG OutChannelLifetime;
  19187. ULONG InProxyReceiveWindow;
  19188. ULONG InProxyConnectionTimeout;
  19189. ULONG OutProxyConnectionTimeout;
  19190. HTTP2Cookie AssociationGroupId;
  19191. ChannelSettingClientAddress ClientAddress;
  19192. HTTP2ServerVirtualConnection *LocalServerConnection;
  19193. HTTP2ServerVirtualConnection *VCPlaceHolder;
  19194. BOOL FirstLeg;
  19195. BOOL AbortServerConnection = FALSE;
  19196. HTTP2ServerChannel *ThisChannel;
  19197. HTTP2ChannelPointer *OtherChannelPtr;
  19198. HTTP2SendContext *D1_C1Context;
  19199. HTTP2SendContext *D1_B3Context;
  19200. HTTP2SendContext *D2_A3Context;
  19201. HTTP2SendContext *D4_A4Context;
  19202. HTTP2SendContext *D4_A5Context;
  19203. int NonDefaultChannel;
  19204. *VirtualConnectionCreated = FALSE;
  19205. // First, do a little bit of parsing to
  19206. // determine if this is the first request for this connection
  19207. // cookie. If not, join the other connection and destroy the
  19208. // runtime stuff for this one. If yes, build a virtual connection
  19209. RpcStatus = GetFirstServerPacketType(Packet,
  19210. PacketLength,
  19211. &PacketType
  19212. );
  19213. if (RpcStatus != RPC_S_OK)
  19214. {
  19215. RpcFreeBuffer(Packet);
  19216. return RpcStatus;
  19217. }
  19218. if (PacketType == http2fsptD1_A2)
  19219. {
  19220. RpcStatus = ParseD1_A2(Packet,
  19221. PacketLength,
  19222. &ProtocolVersion,
  19223. &ServerCookie,
  19224. &ChannelCookie,
  19225. &OutChannelLifetime,
  19226. &OutProxyReceiveWindow);
  19227. if (RpcStatus != RPC_S_OK)
  19228. return RpcStatus;
  19229. if (OutChannelLifetime < MinimumChannelLifetime)
  19230. return RPC_S_PROTOCOL_ERROR;
  19231. // a request to establish a new out connection
  19232. RpcStatus = AllocateAndInitializeOutChannel (&Connection,
  19233. OutChannelLifetime,
  19234. &OutChannel);
  19235. if (RpcStatus == RPC_S_OK)
  19236. {
  19237. // unplug the newly created out channel
  19238. RpcStatus2 = OutChannel->Unplug ();
  19239. // we know we can't fail here since there are no data in the pipe line
  19240. ASSERT(RpcStatus2 == RPC_S_OK);
  19241. OutChannel->SetPeerReceiveWindow(OutProxyReceiveWindow);
  19242. }
  19243. }
  19244. else if (PacketType == http2fsptD1_B2)
  19245. {
  19246. RpcpMemorySet(&ClientAddress, 0, sizeof(ClientAddress));
  19247. RpcStatus = ParseD1_B2(Packet,
  19248. PacketLength,
  19249. &ProtocolVersion,
  19250. &ServerCookie,
  19251. &ChannelCookie,
  19252. &InProxyReceiveWindow,
  19253. &InProxyConnectionTimeout,
  19254. &AssociationGroupId,
  19255. &ClientAddress
  19256. );
  19257. if (RpcStatus != RPC_S_OK)
  19258. return RpcStatus;
  19259. // a request to establish a new in connection
  19260. RpcStatus = AllocateAndInitializeInChannel (&Connection,
  19261. &InChannel);
  19262. }
  19263. else if (PacketType == http2fsptD2_A2)
  19264. {
  19265. // in channel replacement
  19266. RpcStatus = ParseD2_A2(Packet,
  19267. PacketLength,
  19268. &ProtocolVersion,
  19269. &ServerCookie,
  19270. &ChannelCookie,
  19271. &NewChannelCookie,
  19272. &InProxyReceiveWindow,
  19273. &InProxyConnectionTimeout
  19274. );
  19275. if (RpcStatus != RPC_S_OK)
  19276. return RpcStatus;
  19277. // a request to establish a replacement in connection
  19278. RpcStatus = AllocateAndInitializeInChannel (&Connection,
  19279. &InChannel);
  19280. }
  19281. else
  19282. {
  19283. ASSERT(PacketType == http2fsptD4_A4);
  19284. // out channel replacement
  19285. RpcStatus = ParseD4_A4(Packet,
  19286. PacketLength,
  19287. &ProtocolVersion,
  19288. &ServerCookie,
  19289. &ChannelCookie,
  19290. &NewChannelCookie,
  19291. &OutChannelLifetime,
  19292. &OutProxyReceiveWindow,
  19293. &OutProxyConnectionTimeout
  19294. );
  19295. if (RpcStatus != RPC_S_OK)
  19296. return RpcStatus;
  19297. // a request to establish a replacement out connection
  19298. RpcStatus = AllocateAndInitializeOutChannel (&Connection,
  19299. OutChannelLifetime,
  19300. &OutChannel);
  19301. if (RpcStatus == RPC_S_OK)
  19302. OutChannel->SetPeerReceiveWindow(OutProxyReceiveWindow);
  19303. }
  19304. if (RpcStatus != RPC_S_OK)
  19305. return RpcStatus;
  19306. // take the lower of our and reported version
  19307. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  19308. // figure out whether we arrived first or second
  19309. GetServerCookieCollection()->LockCollection();
  19310. LocalServerConnection =
  19311. (HTTP2ServerVirtualConnection *)GetServerCookieCollection()->FindElement(&ServerCookie);
  19312. if (((PacketType == http2fsptD2_A2) || (PacketType == http2fsptD4_A4))
  19313. && (LocalServerConnection == NULL))
  19314. {
  19315. // we cannot establish a replacement connection if the old one is not around
  19316. OriginalConnection->fAborted = 1;
  19317. OriginalConnection->pReadBuffer = NULL;
  19318. RpcStatus = RPC_P_RECEIVE_FAILED;
  19319. goto AbortFirstLegAndExit;
  19320. }
  19321. if (LocalServerConnection == NULL)
  19322. {
  19323. // we're first. Initialize the server virtual connection
  19324. // we know the server has reserved space for the larger of
  19325. // WS_HTTP2_INITIAL_CONNECTION and HTTP2ServerVirtualConnection.
  19326. // Use the same space.
  19327. VCPlaceHolder = (HTTP2ServerVirtualConnection *)OriginalConnection;
  19328. LocalServerConnection = new (VCPlaceHolder) HTTP2ServerVirtualConnection(&ServerCookie,
  19329. ProtocolVersion,
  19330. &RpcStatus);
  19331. if (RpcStatus == RPC_S_OK)
  19332. {
  19333. // we use the first timer for connection establishment
  19334. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout, InChannelTimer);
  19335. }
  19336. if (RpcStatus != RPC_S_OK)
  19337. {
  19338. LocalServerConnection->HTTP2ServerVirtualConnection::~HTTP2ServerVirtualConnection();
  19339. OriginalConnection->fAborted = 1;
  19340. OriginalConnection->pReadBuffer = NULL;
  19341. goto AbortFirstLegAndExit;
  19342. }
  19343. *VirtualConnectionCreated = TRUE;
  19344. LocalServerConnection->id = HTTPv2;
  19345. LocalServerConnection->type = COMPLEX_T | SERVER;
  19346. FirstLeg = TRUE;
  19347. }
  19348. else
  19349. {
  19350. // the actual transport connection is by now owned by the channel
  19351. // Create a fake connection in the current location that will no-op on
  19352. // close.
  19353. OriginalConnection->fAborted = 1;
  19354. OriginalConnection->pReadBuffer = NULL;
  19355. if (PacketType == http2fsptD2_A2)
  19356. {
  19357. // if this is a replacement channel, check the cookies
  19358. if (LocalServerConnection->CompareCookieWithDefaultInChannelCookie(&ChannelCookie))
  19359. {
  19360. // cookies don't match. Nuke the newly established channel - it is probably
  19361. // fake
  19362. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19363. goto AbortFirstLegAndExit;
  19364. }
  19365. // we still hold the cookie collection mutex. This synchronizes with
  19366. // aborts
  19367. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout,
  19368. InChannelTimer
  19369. );
  19370. if (RpcStatus != RPC_S_OK)
  19371. goto AbortFirstLegAndExit;
  19372. }
  19373. else if (PacketType == http2fsptD4_A4)
  19374. {
  19375. // if this is a replacement channel, check the cookies
  19376. if (LocalServerConnection->CompareCookieWithDefaultOutChannelCookie(&ChannelCookie))
  19377. {
  19378. // cookies don't match. Nuke the newly established channel - it is probably
  19379. // fake
  19380. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19381. goto AbortFirstLegAndExit;
  19382. }
  19383. // we still hold the cookie collection mutex. This synchronizes with
  19384. // aborts
  19385. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout,
  19386. OutChannelTimer
  19387. );
  19388. if (RpcStatus != RPC_S_OK)
  19389. goto AbortFirstLegAndExit;
  19390. }
  19391. FirstLeg = FALSE;
  19392. }
  19393. // set the runtime connection ptr for the raw connection
  19394. Connection->RuntimeConnectionPtr = LocalServerConnection;
  19395. // add the raw connection to the PnP list
  19396. TransportProtocol::AddObjectToProtocolList(Connection);
  19397. LocalServerConnection->ProtocolVersion = ProtocolVersion;
  19398. if (PacketType == http2fsptD1_A2)
  19399. {
  19400. if (LocalServerConnection->OutChannels[0].IsChannelSet())
  19401. {
  19402. // if we already have a second channel, then this is a protocol error
  19403. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19404. goto AbortSecondLegAndExit;
  19405. }
  19406. LocalServerConnection->OutProxySettings[0].ReceiveWindow = OutProxyReceiveWindow;
  19407. LocalServerConnection->OutProxySettings[0].ChannelLifetime = OutChannelLifetime;
  19408. LocalServerConnection->OutChannelCookies[0].SetCookie(ChannelCookie.GetCookie());
  19409. // attach the newly created stack to the connection
  19410. LocalServerConnection->SetFirstOutChannel(OutChannel);
  19411. OutChannel->SetParent(LocalServerConnection);
  19412. if (FirstLeg)
  19413. {
  19414. ASSERT(LocalServerConnection->InChannelState.State == http2svClosed);
  19415. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svB2W, 1, 0);
  19416. LocalServerConnection->InChannelState.State = http2svB2W;
  19417. GetServerCookieCollection()->AddElement(&LocalServerConnection->EmbeddedConnectionCookie);
  19418. }
  19419. else
  19420. {
  19421. // we got the second leg - cancel the timeout for the second leg
  19422. LocalServerConnection->CancelTimeout(InChannelTimer);
  19423. if (LocalServerConnection->InChannelState.State != http2svA2W)
  19424. {
  19425. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19426. goto AbortSecondLegAndExit;
  19427. }
  19428. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  19429. LocalServerConnection->InChannelState.State = http2svOpened;
  19430. LocalServerConnection->OutChannelState.State = http2svOpened;
  19431. ASSERT(InChannel == NULL);
  19432. InChannel = LocalServerConnection->LockDefaultInChannel(&OtherChannelPtr);
  19433. if (InChannel == NULL)
  19434. {
  19435. RpcStatus = RPC_P_RECEIVE_FAILED;
  19436. goto AbortSecondLegAndExit;
  19437. }
  19438. InChannel->AddReference();
  19439. OtherChannelPtr->UnlockChannelPointer();
  19440. // for second leg, we need to add one reference before we release
  19441. // the lock. Otherwise the pending receive on the first leg may
  19442. // kill the connection and the channel with it
  19443. OutChannel->AddReference();
  19444. }
  19445. }
  19446. else if ((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD2_A2))
  19447. {
  19448. if (PacketType == http2fsptD1_B2)
  19449. {
  19450. if (FirstLeg == FALSE)
  19451. {
  19452. // we got the second leg - cancel the timeout for the second leg
  19453. LocalServerConnection->CancelTimeout(InChannelTimer);
  19454. }
  19455. CopyClientAddress(&LocalServerConnection->ClientAddress,
  19456. &ClientAddress);
  19457. LocalServerConnection->InProxyReceiveWindows[0] = InProxyReceiveWindow;
  19458. LocalServerConnection->InProxyConnectionTimeout = InProxyConnectionTimeout;
  19459. LocalServerConnection->AssociationGroupId.SetCookie(AssociationGroupId.GetCookie());
  19460. LocalServerConnection->InChannelCookies[0].SetCookie(ChannelCookie.GetCookie());
  19461. // attach the newly created stack to the connection
  19462. LocalServerConnection->SetFirstInChannel(InChannel);
  19463. InChannel->SetParent(LocalServerConnection);
  19464. }
  19465. else
  19466. {
  19467. ASSERT(PacketType == http2fsptD2_A2);
  19468. NonDefaultChannel = LocalServerConnection->GetNonDefaultInChannelSelector();
  19469. LocalServerConnection->InProxyReceiveWindows[NonDefaultChannel] = InProxyReceiveWindow;
  19470. LocalServerConnection->InProxyConnectionTimeout = InProxyConnectionTimeout;
  19471. LocalServerConnection->InChannelCookies[NonDefaultChannel].SetCookie(NewChannelCookie.GetCookie());
  19472. // attach the newly created stack to the connection
  19473. LocalServerConnection->SetNonDefaultInChannel(InChannel);
  19474. InChannel->SetParent(LocalServerConnection);
  19475. if (LocalServerConnection->InChannelState.State != http2svOpened)
  19476. {
  19477. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19478. goto AbortSecondLegAndExit;
  19479. }
  19480. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened_A6W, 1, 0);
  19481. LocalServerConnection->InChannelState.State = http2svOpened_A6W;
  19482. ASSERT(FirstLeg == FALSE);
  19483. }
  19484. if (FirstLeg)
  19485. {
  19486. ASSERT(LocalServerConnection->InChannelState.State == http2svClosed);
  19487. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svA2W, 1, 0);
  19488. LocalServerConnection->InChannelState.State = http2svA2W;
  19489. GetServerCookieCollection()->AddElement(&LocalServerConnection->EmbeddedConnectionCookie);
  19490. }
  19491. else
  19492. {
  19493. if (PacketType == http2fsptD1_B2)
  19494. {
  19495. if (LocalServerConnection->InChannelState.State != http2svB2W)
  19496. {
  19497. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19498. goto AbortSecondLegAndExit;
  19499. }
  19500. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  19501. LocalServerConnection->InChannelState.State = http2svOpened;
  19502. LocalServerConnection->OutChannelState.State = http2svOpened;
  19503. }
  19504. else
  19505. {
  19506. ASSERT(PacketType == http2fsptD2_A2);
  19507. }
  19508. ASSERT(OutChannel == NULL);
  19509. OutChannel = LocalServerConnection->LockDefaultOutChannel(&OtherChannelPtr);
  19510. if (OutChannel == NULL)
  19511. {
  19512. RpcStatus = RPC_P_RECEIVE_FAILED;
  19513. goto AbortSecondLegAndExit;
  19514. }
  19515. OutChannel->AddReference();
  19516. OtherChannelPtr->UnlockChannelPointer();
  19517. // for second leg, we need to add one reference before we release
  19518. // the lock. Otherwise the pending receive on the first leg may
  19519. // kill the connection and the channel with it
  19520. InChannel->AddReference();
  19521. }
  19522. }
  19523. else if (PacketType == http2fsptD4_A4)
  19524. {
  19525. NonDefaultChannel = LocalServerConnection->GetNonDefaultOutChannelSelector();
  19526. LocalServerConnection->OutProxySettings[NonDefaultChannel].ReceiveWindow = OutProxyReceiveWindow;
  19527. LocalServerConnection->OutChannelCookies[NonDefaultChannel].SetCookie(NewChannelCookie.GetCookie());
  19528. // attach the newly created stack to the connection
  19529. LocalServerConnection->SetNonDefaultOutChannel(OutChannel);
  19530. OutChannel->SetParent(LocalServerConnection);
  19531. if (LocalServerConnection->OutChannelState.State != http2svOpened_A4W)
  19532. {
  19533. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19534. goto AbortSecondLegAndExit;
  19535. }
  19536. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, OUT_CHANNEL_STATE, http2svOpened_A8W, 1, 0);
  19537. LocalServerConnection->OutChannelState.State = http2svOpened_A8W;
  19538. ASSERT(FirstLeg == FALSE);
  19539. ASSERT(InChannel == NULL);
  19540. InChannel = LocalServerConnection->LockDefaultInChannel(&OtherChannelPtr);
  19541. if (InChannel == NULL)
  19542. {
  19543. RpcStatus = RPC_P_RECEIVE_FAILED;
  19544. goto AbortSecondLegAndExit;
  19545. }
  19546. InChannel->AddReference();
  19547. OtherChannelPtr->UnlockChannelPointer();
  19548. // for second leg, we need to add one reference before we release
  19549. // the lock. Otherwise the pending receive on the first leg may
  19550. // kill the connection and the channel with it
  19551. OutChannel->AddReference();
  19552. }
  19553. else
  19554. {
  19555. ASSERT(0);
  19556. }
  19557. // N.B. It is safe to release the lock without having sent packets
  19558. // If caller sends data packets without these being sent, we don't care.
  19559. // During the second leg we have an extra reference on both channels, so
  19560. // we can party outside the lock.
  19561. GetServerCookieCollection()->UnlockCollection();
  19562. // we have a virtual connection and at least one of its channels
  19563. // attached to it. We have a no-op connection in OriginalConnection
  19564. // by now. Any failure paths on the second leg must abort the virtual connection
  19565. if ((PacketType == http2fsptD1_A2) || (PacketType == http2fsptD4_A4))
  19566. {
  19567. // out channel
  19568. RpcStatus = OutChannel->Receive(http2ttRaw);
  19569. ThisChannel = OutChannel;
  19570. }
  19571. else
  19572. {
  19573. ASSERT((PacketType == http2fsptD1_B2)
  19574. || (PacketType == http2fsptD2_A2) );
  19575. // in channel
  19576. RpcStatus = InChannel->Receive(http2ttRTS);
  19577. if ((PacketType == http2fsptD1_B2) && (RpcStatus == RPC_S_OK))
  19578. {
  19579. // naturally, we're also interested in data receives
  19580. RpcStatus = InChannel->Receive(http2ttData);
  19581. }
  19582. ThisChannel = InChannel;
  19583. }
  19584. if (FirstLeg)
  19585. {
  19586. // this is the first leg. We know we are the only ones parting on
  19587. // the connection. In case of error just return it back. The runtime
  19588. // will turn around and close the connection
  19589. }
  19590. else
  19591. {
  19592. if ((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD1_A2))
  19593. {
  19594. // the connection is fully fleshed out and both channels are plugged. Some
  19595. // additional activity remains. We need to abort the runtime connection
  19596. // for the second leg and remove the extra refcount
  19597. if (RpcStatus == RPC_S_OK)
  19598. {
  19599. // we need to re-obtain the local server connection pointer through a safe mechanism.
  19600. // After we released the collection mutex, it may have been destroyed
  19601. LocalServerConnection = (HTTP2ServerVirtualConnection *) InChannel->LockParentPointer();
  19602. if (LocalServerConnection)
  19603. {
  19604. // we successfully submitted receives. Now send out D1/C1 and D1/B3
  19605. D1_C1Context = AllocateAndInitializeD1_C1(LocalServerConnection->ProtocolVersion,
  19606. LocalServerConnection->InProxyReceiveWindows[0],
  19607. LocalServerConnection->InProxyConnectionTimeout
  19608. );
  19609. if (D1_C1Context != NULL)
  19610. {
  19611. // we don't need to lock it, because we have a reference to it
  19612. RpcStatus = OutChannel->Send(D1_C1Context);
  19613. if (RpcStatus == RPC_S_OK)
  19614. {
  19615. D1_B3Context = AllocateAndInitializeD1_B3(HTTP2DefaultServerReceiveWindow,
  19616. LocalServerConnection->ProtocolVersion
  19617. );
  19618. if (D1_B3Context != NULL)
  19619. {
  19620. RpcStatus = InChannel->Send(D1_B3Context);
  19621. if (RpcStatus != RPC_S_OK)
  19622. FreeRTSPacket(D1_B3Context);
  19623. }
  19624. else
  19625. {
  19626. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19627. }
  19628. }
  19629. else
  19630. {
  19631. FreeRTSPacket(D1_C1Context);
  19632. }
  19633. }
  19634. else
  19635. {
  19636. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19637. }
  19638. InChannel->UnlockParentPointer();
  19639. }
  19640. else
  19641. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  19642. }
  19643. }
  19644. else if (PacketType == http2fsptD2_A2)
  19645. {
  19646. // We have added the second channel to the connection. Keep the ball
  19647. // rolling
  19648. if (RpcStatus == RPC_S_OK)
  19649. {
  19650. // After we released the collection mutex, it may have been destroyed
  19651. LocalServerConnection = (HTTP2ServerVirtualConnection *) OutChannel->LockParentPointer();
  19652. if (LocalServerConnection)
  19653. {
  19654. // we successfully submitted receives. Now send out D2/A3
  19655. D2_A3Context = AllocateAndInitializeD2_A3(fdClient,
  19656. LocalServerConnection->ProtocolVersion,
  19657. LocalServerConnection->InProxyReceiveWindows[NonDefaultChannel],
  19658. LocalServerConnection->InProxyConnectionTimeout
  19659. );
  19660. if (D2_A3Context != NULL)
  19661. {
  19662. // we don't need to lock it, because we have a reference to it.
  19663. RpcStatus = OutChannel->Send(D2_A3Context);
  19664. if (RpcStatus != RPC_S_OK)
  19665. FreeRTSPacket(D2_A3Context);
  19666. }
  19667. else
  19668. {
  19669. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19670. }
  19671. OutChannel->UnlockParentPointer();
  19672. }
  19673. else
  19674. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  19675. }
  19676. }
  19677. else
  19678. {
  19679. ASSERT(PacketType == http2fsptD4_A4);
  19680. // We have added the second channel to the connection. Keep the ball
  19681. // rolling
  19682. if (RpcStatus == RPC_S_OK)
  19683. {
  19684. // After we released the collection mutex, it may have been destroyed
  19685. LocalServerConnection = (HTTP2ServerVirtualConnection *) OutChannel->LockParentPointer();
  19686. if (LocalServerConnection)
  19687. {
  19688. // we successfully submitted receives. Now send out D4/A5
  19689. D4_A5Context = AllocateAndInitializeD4_A5(fdClient,
  19690. LocalServerConnection->ProtocolVersion,
  19691. OutProxyConnectionTimeout
  19692. );
  19693. if (D4_A5Context != NULL)
  19694. {
  19695. // We still need to send on the default channel. Obtain
  19696. // a pointer through the virtual connection
  19697. RpcStatus = LocalServerConnection->SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  19698. D4_A5Context
  19699. );
  19700. if (RpcStatus != RPC_S_OK)
  19701. FreeRTSPacket(D4_A5Context);
  19702. }
  19703. else
  19704. {
  19705. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19706. }
  19707. OutChannel->UnlockParentPointer();
  19708. }
  19709. else
  19710. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  19711. }
  19712. }
  19713. if (RpcStatus != RPC_S_OK)
  19714. {
  19715. // we can't directly access the connection because we don't have
  19716. // a way to prevent it from going away underneath us. We do it through
  19717. // the channels instead (on which we do have a refcount)
  19718. LocalServerConnection = (HTTP2ServerVirtualConnection *)ThisChannel->LockParentPointer();
  19719. if (LocalServerConnection)
  19720. {
  19721. LocalServerConnection->AbortChannels(RpcStatus);
  19722. ThisChannel->UnlockParentPointer();
  19723. }
  19724. }
  19725. InChannel->RemoveReference();
  19726. OutChannel->RemoveReference();
  19727. if (RpcStatus == RPC_S_OK)
  19728. {
  19729. // fake failure to the runtime. We have migrated our transport connection
  19730. // to the virtual connection and we don't need this one anymore
  19731. RpcStatus = RPC_P_RECEIVE_FAILED;
  19732. }
  19733. }
  19734. return RpcStatus;
  19735. AbortSecondLegAndExit:
  19736. ASSERT(FirstLeg == FALSE);
  19737. // make sure we have no-op'ed the OriginalConnection
  19738. ASSERT(OriginalConnection->fAborted > 0);
  19739. ASSERT(OriginalConnection->pReadBuffer == NULL);
  19740. LocalServerConnection->Abort();
  19741. GetServerCookieCollection()->UnlockCollection();
  19742. // unlink the added connection from the PnP list
  19743. TransportProtocol::RemoveObjectFromProtocolList(Connection);
  19744. // the original connection must be WS_HTTP2_INITIAL_CONNECTION
  19745. ASSERT(OriginalConnection->id == HTTP);
  19746. ASSERT(RpcStatus != RPC_S_OK);
  19747. return RpcStatus;
  19748. AbortFirstLegAndExit:
  19749. // we failed to create a server connection. Release all locks and fail
  19750. GetServerCookieCollection()->UnlockCollection();
  19751. // the original connection must be WS_HTTP2_INITIAL_CONNECTION
  19752. ASSERT(OriginalConnection->id == HTTP);
  19753. // destroy the channel created during the first leg
  19754. if ((PacketType == http2fsptD1_A2) || (PacketType == http2fsptD4_A4))
  19755. {
  19756. OutChannel->Abort(RpcStatus);
  19757. OutChannel->RemoveReference();
  19758. }
  19759. else
  19760. {
  19761. ASSERT((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD2_A2));
  19762. InChannel->Abort(RpcStatus);
  19763. InChannel->RemoveReference();
  19764. }
  19765. ASSERT(RpcStatus != RPC_S_OK);
  19766. return RpcStatus;
  19767. }
  19768. RPC_STATUS HTTP2ServerVirtualConnection::AllocateAndInitializeInChannel (
  19769. IN OUT WS_HTTP2_INITIAL_CONNECTION **Connection,
  19770. OUT HTTP2ServerInChannel **ReturnInChannel
  19771. )
  19772. /*++
  19773. Routine Description:
  19774. Initializes a server in channel.
  19775. Note: This function must migrate the WS_HTTP2_INITIAL_CONNECTION after
  19776. morphing it into WS_HTTP2_CONNECTION
  19777. Arguments:
  19778. Connection - on input, the received connection. It must be migrated
  19779. and morphed into WS_HTTP2_CONNECTION on success. All failure paths
  19780. must be sure to move the WS_HTTP2_INITIAL_CONNECTION back to its
  19781. original location.
  19782. ReturnInChannel - on successful return, the created server in channel
  19783. Return Value:
  19784. RPC_S_OK or RPC_S_* for error
  19785. --*/
  19786. {
  19787. ULONG MemorySize;
  19788. BYTE *MemoryBlock, *CurrentBlock;
  19789. HTTP2ServerInChannel *InChannel;
  19790. HTTP2EndpointReceiver *EndpointReceiver;
  19791. HTTP2SocketTransportChannel *RawChannel;
  19792. WS_HTTP2_CONNECTION *RawConnection;
  19793. BOOL EndpointReceiverNeedsCleanup;
  19794. BOOL RawChannelNeedsCleanup;
  19795. RPC_STATUS RpcStatus;
  19796. // alocate the in channel
  19797. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerInChannel)
  19798. + SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver)
  19799. + SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  19800. + sizeof(WS_HTTP2_CONNECTION);
  19801. MemoryBlock = (BYTE *) new char [MemorySize];
  19802. CurrentBlock = MemoryBlock;
  19803. if (CurrentBlock == NULL)
  19804. return RPC_S_OUT_OF_MEMORY;
  19805. InChannel = (HTTP2ServerInChannel *) MemoryBlock;
  19806. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerInChannel);
  19807. EndpointReceiver = (HTTP2EndpointReceiver *) CurrentBlock;
  19808. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver);
  19809. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  19810. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  19811. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  19812. // all memory blocks are allocated. Go and initialize them. Use explicit
  19813. // placement
  19814. EndpointReceiverNeedsCleanup = FALSE;
  19815. RawChannelNeedsCleanup = FALSE;
  19816. // Wait for any pending IO to get out.
  19817. while((*Connection)->IsIoStarting())
  19818. Sleep(1);
  19819. RpcpMemoryCopy(RawConnection, *Connection, sizeof(WS_HTTP2_CONNECTION));
  19820. RawConnection->HeaderRead = TRUE;
  19821. RawConnection->ReadHeaderFn = NULL;
  19822. RawConnection->Read.pAsyncObject = RawConnection;
  19823. RawConnection->type = COMPLEX_T | CONNECTION | SERVER;
  19824. RawConnection->fAborted = 1; // this connection must not be aborted
  19825. // unless we successfully initialize
  19826. // the channel. Therefore, artificially
  19827. // abort the connection (preventing real
  19828. // aborts) until we initialize the channel
  19829. RawConnection = new (RawConnection) WS_HTTP2_CONNECTION;
  19830. RpcStatus = RPC_S_OK;
  19831. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  19832. if (RpcStatus != RPC_S_OK)
  19833. {
  19834. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  19835. goto AbortAndExit;
  19836. }
  19837. RawConnection->Channel = RawChannel;
  19838. RawChannelNeedsCleanup = TRUE;
  19839. EndpointReceiver = new (EndpointReceiver) HTTP2EndpointReceiver (HTTP2ServerReceiveWindow,
  19840. TRUE, // IsServer
  19841. &RpcStatus);
  19842. if (RpcStatus != RPC_S_OK)
  19843. {
  19844. EndpointReceiver->HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  19845. goto AbortAndExit;
  19846. }
  19847. RawChannel->SetUpperChannel(EndpointReceiver);
  19848. EndpointReceiver->SetLowerChannel(RawChannel);
  19849. EndpointReceiverNeedsCleanup = TRUE;
  19850. InChannel = new (InChannel) HTTP2ServerInChannel (&RpcStatus);
  19851. if (RpcStatus != RPC_S_OK)
  19852. {
  19853. InChannel->HTTP2ServerInChannel::~HTTP2ServerInChannel();
  19854. goto AbortAndExit;
  19855. }
  19856. EndpointReceiver->SetUpperChannel(InChannel);
  19857. InChannel->SetLowerChannel(EndpointReceiver);
  19858. RawChannel->SetTopChannel(InChannel);
  19859. EndpointReceiver->SetTopChannel(InChannel);
  19860. ASSERT(RpcStatus == RPC_S_OK);
  19861. RawConnection->fAborted = 0;
  19862. *ReturnInChannel = InChannel;
  19863. *Connection = (WS_HTTP2_INITIAL_CONNECTION *)RawConnection;
  19864. goto CleanupAndExit;
  19865. AbortAndExit:
  19866. ASSERT(RpcStatus != RPC_S_OK);
  19867. if (EndpointReceiverNeedsCleanup)
  19868. {
  19869. EndpointReceiver->Abort(RpcStatus);
  19870. EndpointReceiver->FreeObject();
  19871. }
  19872. else if (RawChannelNeedsCleanup)
  19873. {
  19874. RawChannel->Abort(RpcStatus);
  19875. RawChannel->FreeObject();
  19876. }
  19877. // no need to clean up the raw connection.
  19878. // If we failed, the virtual connection
  19879. // is not created, and the caller will abort
  19880. // the original conneciton
  19881. if (MemoryBlock)
  19882. delete [] MemoryBlock;
  19883. CleanupAndExit:
  19884. return RpcStatus;
  19885. }
  19886. RPC_STATUS HTTP2ServerVirtualConnection::AllocateAndInitializeOutChannel (
  19887. IN OUT WS_HTTP2_INITIAL_CONNECTION **Connection,
  19888. IN ULONG OutChannelLifetime,
  19889. OUT HTTP2ServerOutChannel **ReturnOutChannel
  19890. )
  19891. /*++
  19892. Routine Description:
  19893. Initializes a server out channel.
  19894. Note: This function must migrate the WS_HTTP2_INITIAL_CONNECTION after
  19895. morphing it into WS_HTTP2_CONNECTION
  19896. Arguments:
  19897. Connection - on input, the received connection. It must be migrated
  19898. and morphed into WS_HTTP2_CONNECTION on success. All failure paths
  19899. must be sure to move the WS_HTTP2_INITIAL_CONNECTION back to its
  19900. original location.
  19901. OutChannelLifetime - the lifetime on the out channel.
  19902. ReturnOutChannel - on successful return, the created server out channel
  19903. Return Value:
  19904. RPC_S_OK or RPC_S_* for error
  19905. --*/
  19906. {
  19907. ULONG MemorySize;
  19908. BYTE *MemoryBlock, *CurrentBlock;
  19909. HTTP2ServerOutChannel *OutChannel;
  19910. HTTP2PlugChannel *PlugChannel;
  19911. HTTP2FlowControlSender *FlowControlSender;
  19912. HTTP2ChannelDataOriginator *ChannelDataOriginator;
  19913. HTTP2SocketTransportChannel *RawChannel;
  19914. WS_HTTP2_CONNECTION *RawConnection;
  19915. BOOL PlugChannelNeedsCleanup;
  19916. BOOL FlowControlSenderNeedsCleanup;
  19917. BOOL ChannelDataOriginatorNeedsCleanup;
  19918. BOOL RawChannelNeedsCleanup;
  19919. RPC_STATUS RpcStatus;
  19920. // alocate the out channel
  19921. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerOutChannel)
  19922. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel)
  19923. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  19924. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator)
  19925. + SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  19926. + SIZE_OF_OBJECT_AND_PADDING(WS_HTTP2_CONNECTION)
  19927. + sizeof(HTTP2SendContext) // send context for the last send
  19928. ;
  19929. MemoryBlock = (BYTE *) new char [MemorySize];
  19930. CurrentBlock = MemoryBlock;
  19931. if (CurrentBlock == NULL)
  19932. return RPC_S_OUT_OF_MEMORY;
  19933. OutChannel = (HTTP2ServerOutChannel *) MemoryBlock;
  19934. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerOutChannel);
  19935. PlugChannel = (HTTP2PlugChannel *) CurrentBlock;
  19936. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel);
  19937. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  19938. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  19939. ChannelDataOriginator = (HTTP2ChannelDataOriginator *)CurrentBlock;
  19940. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator);
  19941. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  19942. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  19943. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  19944. // all memory blocks are allocated. Go and initialize them. Use explicit
  19945. // placement
  19946. PlugChannelNeedsCleanup = FALSE;
  19947. FlowControlSenderNeedsCleanup = FALSE;
  19948. ChannelDataOriginatorNeedsCleanup = FALSE;
  19949. RawChannelNeedsCleanup = FALSE;
  19950. // migrate the connection to its new location. Since nobody points to it (we have
  19951. // been unlinked from the PnP list), copying is sufficient
  19952. // Wait for any pending IO to get out.
  19953. while((*Connection)->IsIoStarting())
  19954. Sleep(1);
  19955. RpcpMemoryCopy(RawConnection, *Connection, sizeof(WS_HTTP2_CONNECTION));
  19956. RawConnection->HeaderRead = TRUE;
  19957. RawConnection->Read.pAsyncObject = RawConnection;
  19958. RawConnection->type = COMPLEX_T | CONNECTION | SERVER;
  19959. RawConnection->fAborted = 1; // this connection must not be aborted
  19960. // unless we successfully initialize
  19961. // the channel. Therefore, artificially
  19962. // abort the connection (preventing real
  19963. // aborts) until we initialize the channel
  19964. RawConnection = new (RawConnection) WS_HTTP2_CONNECTION;
  19965. RpcStatus = RPC_S_OK;
  19966. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  19967. if (RpcStatus != RPC_S_OK)
  19968. {
  19969. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  19970. goto AbortAndExit;
  19971. }
  19972. RawConnection->Channel = RawChannel;
  19973. RawChannelNeedsCleanup = TRUE;
  19974. ChannelDataOriginator = new (ChannelDataOriginator) HTTP2ChannelDataOriginator (OutChannelLifetime,
  19975. TRUE, // IsServer
  19976. &RpcStatus);
  19977. if (RpcStatus != RPC_S_OK)
  19978. {
  19979. ChannelDataOriginator->HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  19980. goto AbortAndExit;
  19981. }
  19982. RawChannel->SetUpperChannel(ChannelDataOriginator);
  19983. ChannelDataOriginator->SetLowerChannel(RawChannel);
  19984. ChannelDataOriginatorNeedsCleanup = TRUE;
  19985. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (TRUE, // IsServer
  19986. TRUE, // SendToRuntime
  19987. &RpcStatus
  19988. );
  19989. if (RpcStatus != RPC_S_OK)
  19990. {
  19991. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  19992. goto AbortAndExit;
  19993. }
  19994. ChannelDataOriginator->SetUpperChannel(FlowControlSender);
  19995. FlowControlSender->SetLowerChannel(ChannelDataOriginator);
  19996. FlowControlSenderNeedsCleanup = TRUE;
  19997. PlugChannel = new (PlugChannel) HTTP2PlugChannel (&RpcStatus);
  19998. if (RpcStatus != RPC_S_OK)
  19999. {
  20000. PlugChannel->HTTP2PlugChannel::~HTTP2PlugChannel();
  20001. goto AbortAndExit;
  20002. }
  20003. FlowControlSender->SetUpperChannel(PlugChannel);
  20004. PlugChannel->SetLowerChannel(FlowControlSender);
  20005. PlugChannelNeedsCleanup = TRUE;
  20006. OutChannel = new (OutChannel) HTTP2ServerOutChannel (&RpcStatus);
  20007. if (RpcStatus != RPC_S_OK)
  20008. {
  20009. OutChannel->HTTP2ServerOutChannel::~HTTP2ServerOutChannel();
  20010. goto AbortAndExit;
  20011. }
  20012. RawChannel->SetTopChannel(OutChannel);
  20013. ChannelDataOriginator->SetTopChannel(OutChannel);
  20014. FlowControlSender->SetTopChannel(OutChannel);
  20015. PlugChannel->SetTopChannel(OutChannel);
  20016. PlugChannel->SetUpperChannel(OutChannel);
  20017. OutChannel->SetLowerChannel(PlugChannel);
  20018. ASSERT(RpcStatus == RPC_S_OK);
  20019. RawConnection->fAborted = 0;
  20020. *ReturnOutChannel = OutChannel;
  20021. *Connection = (WS_HTTP2_INITIAL_CONNECTION *)RawConnection;
  20022. goto CleanupAndExit;
  20023. AbortAndExit:
  20024. if (PlugChannelNeedsCleanup)
  20025. {
  20026. PlugChannel->Abort(RpcStatus);
  20027. PlugChannel->FreeObject();
  20028. }
  20029. else if (FlowControlSenderNeedsCleanup)
  20030. {
  20031. FlowControlSender->Abort(RpcStatus);
  20032. FlowControlSender->FreeObject();
  20033. }
  20034. else if (ChannelDataOriginatorNeedsCleanup)
  20035. {
  20036. ChannelDataOriginator->Abort(RpcStatus);
  20037. ChannelDataOriginator->FreeObject();
  20038. }
  20039. else if (RawChannelNeedsCleanup)
  20040. {
  20041. RawChannel->Abort(RpcStatus);
  20042. RawChannel->FreeObject();
  20043. }
  20044. // no need to clean up the raw connection.
  20045. // If we failed, the virtual connection
  20046. // is not created, and the caller will abort
  20047. // the original conneciton
  20048. if (MemoryBlock)
  20049. delete [] MemoryBlock;
  20050. CleanupAndExit:
  20051. return RpcStatus;
  20052. }
  20053. void HTTP2ServerVirtualConnection::TimeoutExpired (
  20054. void
  20055. )
  20056. /*++
  20057. Routine Description:
  20058. A timeout expired before we cancelled the timer. Abort the connection.
  20059. Arguments:
  20060. Return Value:
  20061. --*/
  20062. {
  20063. TimerExpiredNotify();
  20064. AbortChannels(RPC_P_TIMEOUT);
  20065. }