Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

27291 lines
813 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 HTTP2PingTimerCallback(
  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 address of a TimerContext 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. TimerContext *pTimer;
  649. RPC_STATUS RpcStatus;
  650. ASSERT(TimerOrWaitFired);
  651. // REVIEW - if this fails, offload to an RPC worker thread?
  652. ThreadSelf();
  653. pTimer = (TimerContext *)lpParameter;
  654. pTimer->Parent->TimeoutExpired(pTimer);
  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. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DELAYED_RECV,
  710. TransportChannel
  711. );
  712. break;
  713. case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
  714. ASSERT(TransportChannel->State == whtcsReceivedResponse);
  715. TransportChannel->AsyncError = RPC_S_OK;
  716. // Get the bytes read.
  717. // Since we query for the data available before a receive, we should
  718. // receive at least the amount the query has promissed.
  719. ASSERT(TransportChannel->NumberOfBytesTransferred <= dwStatusInformationLength);
  720. TransportChannel->NumberOfBytesTransferred = dwStatusInformationLength;
  721. // This signals the async completion of WinHttpRead.
  722. ASSERT(TransportChannel->SyncEvent);
  723. SetEvent(TransportChannel->SyncEvent);
  724. break;
  725. case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
  726. if (TransportChannel->State == whtcsDraining)
  727. {
  728. // harvest the bytes available
  729. TransportChannel->AsyncError = RPC_S_OK;
  730. TransportChannel->NumberOfBytesTransferred = *(ULONG *)lpvStatusInformation;
  731. TransportChannel->ContinueDrainChannel();
  732. }
  733. else
  734. {
  735. ASSERT(TransportChannel->State == whtcsReading);
  736. TransportChannel->State = whtcsReceivedResponse;
  737. // A read has completed asyncronously - issue a callback.
  738. TransportChannel->AsyncError = RPC_S_OK;
  739. // harvest the bytes available
  740. TransportChannel->NumberOfBytesTransferred = *(ULONG *)lpvStatusInformation;
  741. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  742. TransportChannel
  743. );
  744. }
  745. break;
  746. case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
  747. ASSERT(TransportChannel->State == whtcsWriting);
  748. TransportChannel->AsyncError = RPC_S_OK;
  749. // get the bytes written
  750. TransportChannel->NumberOfBytesTransferred = *(ULONG *)lpvStatusInformation;
  751. // A write has completed asyncronously - issue a callback.
  752. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  753. TransportChannel
  754. );
  755. break;
  756. case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
  757. // An async IO has failed. The async IO that can be outstanding is
  758. // from the following APIs:
  759. //
  760. // WinHttpSendRequest, WinHttpReceiveResponse, WinHttpReadData,
  761. // WinHttpWriteData.
  762. //
  763. // Conditions when async IO is outstanding for these APIs correpsond to the
  764. // states of: whtcsSendingRequest, whtcsReceivingResponse, whtcsReading,
  765. // whtcsWriting respectively.
  766. //
  767. // We are also notified of the failed API via dwResult field of WINHTTP_ASYNC_RESULT.
  768. //
  769. // WinHttpSendRequest and WinHttpReceiveResponse will wait for SyncEvent
  770. // to be raised. We will notify them of the failure by setting AsyncError.
  771. // WinHttpReadData and WinHttpWriteData failures will be propagated to the upper layers
  772. // via an async callback.
  773. //
  774. AsyncResult = (WINHTTP_ASYNC_RESULT *) lpvStatusInformation;
  775. Api = AsyncResult->dwResult;
  776. LOG_FN_OPERATION_ENTRY2(HTTP2LOG_OPERATION_WHTTP_ERROR, HTTP2LOG_OT_WINHTTP_CALLBACK, UlongToPtr(Api), AsyncResult->dwError);
  777. switch (Api)
  778. {
  779. case API_SEND_REQUEST:
  780. ASSERT(TransportChannel->State == whtcsSendingRequest);
  781. // the only two values allowed here are ok or access denied
  782. // (which means we didn't like the server certificate name).
  783. ASSERT((TransportChannel->AsyncError == RPC_S_OK)
  784. || (TransportChannel->AsyncError == RPC_S_INTERNAL_ERROR)
  785. || (TransportChannel->AsyncError == RPC_S_ACCESS_DENIED) );
  786. TransportChannel->State = whtcsSentRequest;
  787. VALIDATE(AsyncResult->dwError)
  788. {
  789. ERROR_WINHTTP_CANNOT_CONNECT,
  790. ERROR_WINHTTP_CONNECTION_ERROR,
  791. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  792. ERROR_WINHTTP_OUT_OF_HANDLES,
  793. ERROR_WINHTTP_REDIRECT_FAILED,
  794. ERROR_WINHTTP_RESEND_REQUEST,
  795. ERROR_WINHTTP_SECURE_FAILURE,
  796. ERROR_WINHTTP_SHUTDOWN,
  797. ERROR_WINHTTP_TIMEOUT,
  798. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  799. ERROR_NOT_ENOUGH_MEMORY,
  800. ERROR_COMMITMENT_LIMIT,
  801. ERROR_WINHTTP_OPERATION_CANCELLED,
  802. ERROR_WINHTTP_INTERNAL_ERROR
  803. } END_VALIDATE;
  804. ASSERT (AsyncResult->dwError != ERROR_WINHTTP_RESEND_REQUEST);
  805. // if not access denied, make it send failed
  806. if (TransportChannel->AsyncError != RPC_S_ACCESS_DENIED)
  807. TransportChannel->AsyncError = RPC_P_SEND_FAILED;
  808. ASSERT(TransportChannel->SyncEvent);
  809. SetEvent(TransportChannel->SyncEvent);
  810. break;
  811. case API_READ_DATA:
  812. ASSERT(TransportChannel->State == whtcsReceivedResponse);
  813. VALIDATE(AsyncResult->dwError)
  814. {
  815. ERROR_WINHTTP_CONNECTION_ERROR
  816. } END_VALIDATE;
  817. // This signals the async completion of WinHttpRead.
  818. TransportChannel->AsyncError = RPC_P_RECEIVE_FAILED;
  819. ASSERT(TransportChannel->SyncEvent);
  820. SetEvent(TransportChannel->SyncEvent);
  821. break;
  822. case API_RECEIVE_RESPONSE:
  823. ASSERT(TransportChannel->State == whtcsReceivingResponse);
  824. TransportChannel->State = whtcsReceivedResponse;
  825. VALIDATE(AsyncResult->dwError)
  826. {
  827. ERROR_WINHTTP_CANNOT_CONNECT,
  828. ERROR_WINHTTP_CONNECTION_ERROR,
  829. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  830. ERROR_WINHTTP_OUT_OF_HANDLES,
  831. ERROR_WINHTTP_REDIRECT_FAILED,
  832. ERROR_WINHTTP_RESEND_REQUEST,
  833. ERROR_WINHTTP_SECURE_FAILURE,
  834. ERROR_WINHTTP_SHUTDOWN,
  835. ERROR_WINHTTP_TIMEOUT,
  836. ERROR_WINHTTP_OPERATION_CANCELLED,
  837. ERROR_NOT_ENOUGH_MEMORY,
  838. ERROR_COMMITMENT_LIMIT,
  839. ERROR_WINHTTP_LOGIN_FAILURE
  840. } END_VALIDATE;
  841. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  842. TransportChannel->AsyncError = RPC_P_AUTH_NEEDED;
  843. else
  844. TransportChannel->AsyncError = RPC_P_RECEIVE_FAILED;
  845. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DELAYED_RECV,
  846. TransportChannel
  847. );
  848. break;
  849. case API_QUERY_DATA_AVAILABLE:
  850. // if we get closed while receiving data, we can be
  851. // in draining state
  852. ASSERT((TransportChannel->State == whtcsReading)
  853. || (TransportChannel->State == whtcsDraining));
  854. TransportChannel->State = whtcsReceivedResponse;
  855. VALIDATE(AsyncResult->dwError)
  856. {
  857. ERROR_WINHTTP_CANNOT_CONNECT,
  858. ERROR_WINHTTP_CONNECTION_ERROR,
  859. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  860. ERROR_WINHTTP_OUT_OF_HANDLES,
  861. ERROR_WINHTTP_REDIRECT_FAILED,
  862. ERROR_WINHTTP_RESEND_REQUEST,
  863. ERROR_WINHTTP_SECURE_FAILURE,
  864. ERROR_WINHTTP_SHUTDOWN,
  865. ERROR_WINHTTP_TIMEOUT,
  866. ERROR_WINHTTP_OPERATION_CANCELLED
  867. } END_VALIDATE;
  868. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  869. {
  870. ASSERT(0);
  871. }
  872. TransportChannel->AsyncError = RPC_P_RECEIVE_FAILED;
  873. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  874. TransportChannel
  875. );
  876. break;
  877. case API_WRITE_DATA:
  878. ASSERT(TransportChannel->State == whtcsWriting);
  879. VALIDATE(AsyncResult->dwError)
  880. {
  881. ERROR_WINHTTP_CANNOT_CONNECT,
  882. ERROR_WINHTTP_CONNECTION_ERROR,
  883. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  884. ERROR_WINHTTP_OUT_OF_HANDLES,
  885. ERROR_WINHTTP_REDIRECT_FAILED,
  886. ERROR_WINHTTP_RESEND_REQUEST,
  887. ERROR_WINHTTP_SECURE_FAILURE,
  888. ERROR_WINHTTP_SHUTDOWN,
  889. ERROR_WINHTTP_TIMEOUT,
  890. ERROR_WINHTTP_OPERATION_CANCELLED
  891. } END_VALIDATE;
  892. if (AsyncResult->dwError == ERROR_WINHTTP_RESEND_REQUEST)
  893. {
  894. ASSERT(0);
  895. }
  896. TransportChannel->AsyncError = RPC_P_SEND_FAILED;
  897. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  898. TransportChannel
  899. );
  900. break;
  901. default:
  902. ASSERT(0);
  903. }
  904. break;
  905. default:
  906. // don't care about the other notifications
  907. break;
  908. }
  909. LOG_FN_OPERATION_EXIT2(HTTP2LOG_OPERATION_WINHTTP_CALLBACK, HTTP2LOG_OT_WINHTTP_CALLBACK, TransportChannel, dwInternetStatus);
  910. };
  911. RPC_STATUS WaitForSyncSend (
  912. IN BASE_ASYNC_OBJECT *Connection,
  913. IN HTTP2SendContext *SendContext,
  914. IN HTTP2VirtualConnection *Parent,
  915. IN BOOL fDisableCancelCheck,
  916. IN ULONG Timeout
  917. )
  918. /*++
  919. Routine Description:
  920. Waits for a synchronous send to complete.
  921. Arguments:
  922. Connection - run time view of the transport connection
  923. SendContext - the send context
  924. Parent - the parent virtual connection (used to abort)
  925. fDisableCancelCheck - don't do checks for cancels. Can be
  926. used as optimization
  927. Timeout - the call timeout
  928. Return Value:
  929. RPC_S_OK or other RPC_S_* errors for error
  930. --*/
  931. {
  932. RPC_STATUS RpcStatus;
  933. HTTP2Channel *ThisChannel;
  934. // the IO was submitted. Wait for it.
  935. // If fDisableCancelCheck, make the thread wait non-alertably,
  936. // otherwise, make it wait alertably.
  937. RpcStatus = UTIL_GetOverlappedHTTP2ResultEx(Connection,
  938. &SendContext->Write.ol,
  939. SendContext->u.SyncEvent,
  940. !fDisableCancelCheck, // bAlertable
  941. Timeout);
  942. if (RpcStatus != RPC_S_OK)
  943. {
  944. Parent->AbortChannels(RpcStatus);
  945. if ((RpcStatus == RPC_S_CALL_CANCELLED) || (RpcStatus == RPC_P_TIMEOUT))
  946. {
  947. // Wait for the write to finish. Since we closed the
  948. // connection this won't take very long.
  949. UTIL_WaitForSyncHTTP2IO(&SendContext->Write.ol,
  950. SendContext->u.SyncEvent,
  951. FALSE, // fAlertable
  952. INFINITE // Timeout
  953. );
  954. }
  955. }
  956. return(RpcStatus);
  957. }
  958. void
  959. AddBufferQueueToChannel (
  960. IN LIST_ENTRY *NewBufferHead,
  961. IN HTTP2Channel *Channel
  962. )
  963. /*++
  964. Routine Description:
  965. Adds all the send contexts from the queue to the front of given channel.
  966. Presumably the channel has a plug channel down somewhere which does
  967. the actual ordering work
  968. Arguments:
  969. NewBufferHead - the list head of the buffer queue. They are assumed to
  970. be in order.
  971. Channel - the channel to make the sends on
  972. Return Value:
  973. Notes:
  974. The new channel must still be plugged.
  975. --*/
  976. {
  977. HTTP2SendContext *QueuedSendContext;
  978. LIST_ENTRY *CurrentListEntry;
  979. LIST_ENTRY *PrevListEntry;
  980. RPC_STATUS RpcStatus;
  981. // Queue the sends to the front of the new channel
  982. // walk the queue in reverse order and add it to the plug channel
  983. CurrentListEntry = NewBufferHead->Blink;
  984. while (CurrentListEntry != NewBufferHead)
  985. {
  986. QueuedSendContext
  987. = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  988. PrevListEntry = CurrentListEntry->Blink;
  989. QueuedSendContext->Flags |= SendContextFlagPutInFront;
  990. // Setting this flag ensures that the send will not fail even for
  991. // a channel with a pending abort. This is necessary to force a send
  992. // and get the send context queued inside the plug channel.
  993. QueuedSendContext->Flags |= SendContextFlagPluggedChannel;
  994. RpcStatus = Channel->Send(QueuedSendContext);
  995. // since we know the channel is plugged yet, this cannot fail
  996. ASSERT(RpcStatus == RPC_S_OK);
  997. CurrentListEntry = PrevListEntry;
  998. }
  999. }
  1000. void
  1001. RPC_CLIENT_PROCESS_IDENTIFIER::SetHTTP2ClientIdentifier (
  1002. IN void *Buffer,
  1003. IN size_t BufferSize,
  1004. IN BOOL fLocal
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. sets an HTTP2 client identifier
  1009. Arguments:
  1010. Buffer - the buffer with the client identifier.
  1011. BufferSize - the number of bytes containg valid
  1012. info in the buffer.
  1013. fLocal - non-zero if client is local. 0 otherwise.
  1014. Return Value:
  1015. --*/
  1016. {
  1017. BYTE *CurrentPosition;
  1018. this->fLocal = fLocal;
  1019. this->ZeroPadding = 0;
  1020. ASSERT(sizeof(u.ULongClientId) >= BufferSize);
  1021. RpcpMemorySet(u.ULongClientId, 0, sizeof(u.ULongClientId) - BufferSize);
  1022. CurrentPosition = ((BYTE *)u.ULongClientId) + sizeof(u.ULongClientId) - BufferSize;
  1023. RpcpMemoryCopy(CurrentPosition, Buffer, BufferSize);
  1024. }
  1025. RPC_STATUS
  1026. HttpSendIdentifyResponse(
  1027. IN SOCKET Socket
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. <TBS>
  1032. Arguments:
  1033. Socket -
  1034. Return Value:
  1035. None
  1036. --*/
  1037. {
  1038. RPC_STATUS Status = RPC_S_OK;
  1039. int iBytes;
  1040. char *pszId = HTTP_SERVER_ID_STR;
  1041. DWORD dwSize;
  1042. iBytes = send(
  1043. Socket,
  1044. pszId,
  1045. HTTP_SERVER_ID_STR_LEN,
  1046. 0
  1047. );
  1048. if (iBytes == SOCKET_ERROR)
  1049. {
  1050. VALIDATE(GetLastError())
  1051. {
  1052. WSAENETDOWN,
  1053. WSAECONNREFUSED,
  1054. WSAECONNRESET,
  1055. WSAENETRESET,
  1056. WSAETIMEDOUT,
  1057. WSAECONNABORTED,
  1058. WSASYSCALLFAILURE
  1059. } END_VALIDATE;
  1060. Status = RPC_S_OUT_OF_RESOURCES;
  1061. }
  1062. return Status;
  1063. }
  1064. RPC_STATUS
  1065. HTTP_TryConnect( SOCKET Socket,
  1066. char *pszProxyMachine,
  1067. USHORT iPort )
  1068. /*++
  1069. Routine Description:
  1070. Used by HTTP_Open() to actually call the connect(). HTTP_Open() will try
  1071. first to reach the RPC Proxy directly, if it can't then it will call this
  1072. routine again to try to reach an HTTP proxy (i.e. MSProxy for example).
  1073. Arguments:
  1074. Socket - The socket to use in the connect().
  1075. pszProxyMachine - The name of the machine to try to connect() to.
  1076. iPort - The port to connect() on.
  1077. Return Value:
  1078. RPC_S_OK
  1079. RPC_S_OUT_OF_MEMORY
  1080. RPC_S_OUT_OF_RESOURCES
  1081. RPC_S_SERVER_UNAVAILABLE
  1082. RPC_S_INVALID_NET_ADDR
  1083. --*/
  1084. {
  1085. RPC_STATUS Status = RPC_S_OK;
  1086. WS_SOCKADDR ProxyServer;
  1087. RPC_CHAR pwszBuffer[MAX_HTTP_COMPUTERNAME_SIZE+1];
  1088. //
  1089. // Check for empty proxy machine name:
  1090. //
  1091. if ( (!pszProxyMachine) || (*pszProxyMachine == 0))
  1092. {
  1093. return RPC_S_SERVER_UNAVAILABLE;
  1094. }
  1095. memset((char *)&ProxyServer, 0, sizeof(ProxyServer));
  1096. //
  1097. // Resolve the machine name (or dot-notation address) into
  1098. // a network address. If that works then try to connect
  1099. // using the supplied port.
  1100. //
  1101. SimpleAnsiToPlatform(pszProxyMachine,pwszBuffer);
  1102. IP_ADDRESS_RESOLVER resolver(pwszBuffer,
  1103. cosClient,
  1104. ipvtuIPv4 // IP version to use
  1105. );
  1106. Status = resolver.NextAddress(&ProxyServer.inetaddr);
  1107. if (Status == RPC_S_OK)
  1108. {
  1109. ProxyServer.inetaddr.sin_family = AF_INET;
  1110. ProxyServer.inetaddr.sin_port = htons(iPort);
  1111. //
  1112. // Try to connect...
  1113. //
  1114. if (SOCKET_ERROR == connect(Socket,
  1115. (struct sockaddr *)&ProxyServer.inetaddr,
  1116. sizeof(ProxyServer.inetaddr)))
  1117. {
  1118. #if DBG_ERROR
  1119. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  1120. DPFLTR_WARNING_LEVEL,
  1121. "HTTP_Open(): connect() failed: %d\n",
  1122. WSAGetLastError()));
  1123. #endif // DBG_ERROR
  1124. VALIDATE(GetLastError())
  1125. {
  1126. WSAENETDOWN,
  1127. WSAEADDRNOTAVAIL,
  1128. WSAECONNREFUSED,
  1129. WSAECONNABORTED,
  1130. WSAENETUNREACH,
  1131. WSAEHOSTUNREACH,
  1132. WSAENOBUFS,
  1133. WSAETIMEDOUT
  1134. } END_VALIDATE;
  1135. Status = RPC_S_SERVER_UNAVAILABLE;
  1136. }
  1137. }
  1138. return Status;
  1139. }
  1140. RPC_STATUS HTTP2Cookie::Create (
  1141. void
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. Create a cryptographically strong HTTP2 cookie
  1146. Arguments:
  1147. Return Value:
  1148. RPC_S_OK or RPC_S_* failure
  1149. --*/
  1150. {
  1151. return GenerateRandomNumber(Cookie, sizeof(Cookie));
  1152. }
  1153. void HTTPResolverHint::VerifyInitialized (
  1154. void
  1155. )
  1156. /*++
  1157. Routine Description:
  1158. Verify that the resolver hint is properly initialized and consistent
  1159. Arguments:
  1160. Return Value:
  1161. --*/
  1162. {
  1163. ASSERT(RpcServer);
  1164. ASSERT(ServerPort != 0);
  1165. ASSERT(RpcProxy);
  1166. ASSERT(RpcProxyPort != 0);
  1167. if (HTTPProxy)
  1168. {
  1169. ASSERT(HTTPProxyPort != 0);
  1170. }
  1171. }
  1172. RPC_STATUS
  1173. RPC_ENTRY
  1174. HTTP_Initialize (
  1175. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1176. IN RPC_CHAR * /* NetworkAddress */,
  1177. IN RPC_CHAR * /* NetworkOptions */,
  1178. IN BOOL /* fAsync */
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. Called by the runtime to do initial initialization of the transport
  1183. object. The purpose of this initialization is to allow the transport
  1184. to do some minimal initialization sufficient to ensure ordely
  1185. destruction in case of failure.
  1186. Arguments:
  1187. ThisConnection - an uninitialized connection allocated by the runtime
  1188. NetworkAddress - ignored
  1189. NetworkOptions - ignored
  1190. fAsync - ignored
  1191. Return Value:
  1192. RPC_S_OK for success of RPC_S_* / Win32 error for error.
  1193. --*/
  1194. {
  1195. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  1196. BaseObject->id = INVALID_PROTOCOL_ID;
  1197. return RPC_S_OK;
  1198. }
  1199. RPC_STATUS
  1200. RPC_ENTRY
  1201. HTTP_CheckIPAddressForDirectConnection (
  1202. IN HTTPResolverHint *Hint
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. Checks if the rpc proxy server address given in the hint should be used
  1207. for direct connection based on registry settings
  1208. Arguments:
  1209. Hint - the resolver hint
  1210. Return Value:
  1211. RPC_S_OK or RPC_S_* / win32 error code
  1212. --*/
  1213. {
  1214. HKEY RpcOptionsKey;
  1215. DWORD Status;
  1216. DWORD KeyType;
  1217. const RPC_CHAR *UseProxyForIPAddrIfRDNSFailsRegKey = RPC_CONST_STRING("UseProxyForIPAddrIfRDNSFails");
  1218. const RPC_CHAR *RpcRegistryOptions =
  1219. RPC_CONST_STRING("Software\\Microsoft\\Rpc");
  1220. DWORD UseProxyForIPAddrIfRDNSFails;
  1221. DWORD RegKeySize;
  1222. int err;
  1223. ADDRINFO AddrHint;
  1224. ADDRINFO *AddrInfo;
  1225. RpcpMemorySet(&AddrHint, 0, sizeof(ADDRINFO));
  1226. AddrHint.ai_flags = AI_NUMERICHOST;
  1227. err = getaddrinfo(Hint->RpcProxy,
  1228. NULL,
  1229. &AddrHint,
  1230. &AddrInfo
  1231. );
  1232. ASSERT((err != EAI_BADFLAGS)
  1233. && (err != EAI_SOCKTYPE));
  1234. if (err)
  1235. {
  1236. // the address was not numeric. It's not up to us to tell
  1237. // where this should go
  1238. return RPC_S_OK;
  1239. }
  1240. // assume direct connection for now
  1241. Hint->AccessType = rpcpatDirect;
  1242. Status = RegOpenKey( HKEY_LOCAL_MACHINE,
  1243. (const RPC_SCHAR *)RpcRegistryOptions,
  1244. &RpcOptionsKey );
  1245. if (Status != ERROR_SUCCESS)
  1246. {
  1247. // direct connection is already set
  1248. goto CleanupAndExit;
  1249. }
  1250. RegKeySize = sizeof(DWORD);
  1251. Status = RegQueryValueEx(RpcOptionsKey,
  1252. (const RPC_SCHAR *)UseProxyForIPAddrIfRDNSFailsRegKey,
  1253. NULL,
  1254. &KeyType,
  1255. (LPBYTE)&UseProxyForIPAddrIfRDNSFails,
  1256. &RegKeySize);
  1257. RegCloseKey(RpcOptionsKey);
  1258. if ( (Status != ERROR_SUCCESS) ||
  1259. (KeyType != REG_DWORD) )
  1260. {
  1261. // direct connection is already set
  1262. goto CleanupAndExit;
  1263. }
  1264. if (UseProxyForIPAddrIfRDNSFails != 1)
  1265. {
  1266. // direct connection is already set
  1267. goto CleanupAndExit;
  1268. }
  1269. err = getnameinfo(AddrInfo->ai_addr,
  1270. AddrInfo->ai_addrlen,
  1271. NULL,
  1272. 0,
  1273. NULL,
  1274. 0,
  1275. NI_NAMEREQD
  1276. );
  1277. if (err)
  1278. {
  1279. Hint->AccessType = rpcpatHTTPProxy;
  1280. }
  1281. // else
  1282. // direct connection is already set
  1283. CleanupAndExit:
  1284. freeaddrinfo(AddrInfo);
  1285. return RPC_S_OK;
  1286. }
  1287. void
  1288. RPC_ENTRY HTTP_FreeResolverHint (
  1289. IN void *ResolverHint
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. Called by the runtime to free the resolver hint.
  1294. Arguments:
  1295. ResolverHint - the resolver hint created by the transport.
  1296. Return Value:
  1297. --*/
  1298. {
  1299. HTTPResolverHint *Hint = (HTTPResolverHint *)ResolverHint;
  1300. Hint->FreeHTTPProxy();
  1301. Hint->FreeRpcProxy();
  1302. Hint->FreeRpcServer();
  1303. }
  1304. RPC_STATUS
  1305. RPC_ENTRY HTTP_CopyResolverHint (
  1306. IN void *TargetResolverHint,
  1307. IN void *SourceResolverHint,
  1308. IN BOOL SourceWillBeAbandoned
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. Tells the transport to copy the resolver hint from Source to Target
  1313. Arguments:
  1314. TargetResolverHint - pointer to the target resolver hint
  1315. SourceResolverHint - pointer to the source resolver hint
  1316. SourceWillBeAbandoned - non-zero if the source hint was in temporary
  1317. location and will be abandoned. Zero otherwise.
  1318. Return Value:
  1319. if SourceWillBeAbandoned is specified, this function is guaranteed
  1320. to return RPC_S_OK. Otherwise, it may return RPC_S_OUT_OF_MEMORY as well.
  1321. --*/
  1322. {
  1323. HTTPResolverHint *TargetHint = (HTTPResolverHint *)TargetResolverHint;
  1324. HTTPResolverHint *SourceHint = (HTTPResolverHint *)SourceResolverHint;
  1325. ULONG HTTPProxyNameLength;
  1326. ASSERT(TargetHint != SourceHint);
  1327. // bulk copy most of the stuff, and then hand copy few items
  1328. RpcpMemoryCopy(TargetHint, SourceHint, sizeof(HTTPResolverHint));
  1329. if (SourceWillBeAbandoned)
  1330. {
  1331. // the source hint will be abandoned - just hijack all
  1332. // embedded pointers
  1333. if (SourceHint->RpcServer == SourceHint->RpcServerName)
  1334. TargetHint->RpcServer = TargetHint->RpcServerName;
  1335. SourceHint->HTTPProxy = NULL;
  1336. SourceHint->RpcProxy = NULL;
  1337. SourceHint->RpcServer = NULL;
  1338. }
  1339. else
  1340. {
  1341. TargetHint->HTTPProxy = NULL;
  1342. TargetHint->RpcProxy = NULL;
  1343. TargetHint->RpcServer = NULL;
  1344. if (SourceHint->HTTPProxy)
  1345. {
  1346. HTTPProxyNameLength = RpcpStringLengthA(SourceHint->HTTPProxy) + 1;
  1347. TargetHint->HTTPProxy = new char [HTTPProxyNameLength];
  1348. if (TargetHint->HTTPProxy == NULL)
  1349. goto FreeTargetHintAndExit;
  1350. RpcpMemoryCopy(TargetHint->HTTPProxy, SourceHint->HTTPProxy, HTTPProxyNameLength);
  1351. }
  1352. TargetHint->RpcProxy = new char [SourceHint->ProxyNameLength + 1];
  1353. if (TargetHint->RpcProxy == NULL)
  1354. goto FreeTargetHintAndExit;
  1355. RpcpMemoryCopy(TargetHint->RpcProxy, SourceHint->RpcProxy, SourceHint->ProxyNameLength + 1);
  1356. if (SourceHint->RpcServer == SourceHint->RpcServerName)
  1357. TargetHint->RpcServer = TargetHint->RpcServerName;
  1358. else
  1359. {
  1360. TargetHint->RpcServer = new char [SourceHint->ServerNameLength + 1];
  1361. if (TargetHint->RpcServer == NULL)
  1362. goto FreeTargetHintAndExit;
  1363. RpcpMemoryCopy(TargetHint->RpcServer, SourceHint->RpcServer, SourceHint->ServerNameLength + 1);
  1364. }
  1365. }
  1366. return RPC_S_OK;
  1367. FreeTargetHintAndExit:
  1368. TargetHint->FreeHTTPProxy();
  1369. TargetHint->FreeRpcProxy();
  1370. TargetHint->FreeRpcServer();
  1371. return RPC_S_OUT_OF_MEMORY;
  1372. }
  1373. int
  1374. RPC_ENTRY HTTP_CompareResolverHint (
  1375. IN void *ResolverHint1,
  1376. IN void *ResolverHint2
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Tells the transport to compare the given 2 resolver hints
  1381. Arguments:
  1382. ResolverHint1 - pointer to the first resolver hint
  1383. ResolverHint2 - pointer to the second resolver hint
  1384. Return Value:
  1385. (same semantics as memcmp)
  1386. 0 - the resolver hints are equal
  1387. non-zero - the resolver hints are not equal
  1388. --*/
  1389. {
  1390. HTTPResolverHint *Hint1 = (HTTPResolverHint *)ResolverHint1;
  1391. HTTPResolverHint *Hint2 = (HTTPResolverHint *)ResolverHint2;
  1392. if (Hint1->Version != Hint2->Version)
  1393. return 1;
  1394. if (Hint1->ServerPort != Hint2->ServerPort)
  1395. return 1;
  1396. if (Hint1->ServerNameLength != Hint2->ServerNameLength)
  1397. return 1;
  1398. return RpcpMemoryCompare(Hint1->RpcServer, Hint2->RpcServer, Hint1->ServerNameLength);
  1399. }
  1400. RPC_STATUS RPC_ENTRY
  1401. HTTP_SetLastBufferToFree (
  1402. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1403. IN void *Buffer
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. Tells the transport what buffer to free when it is done with the last send
  1408. Arguments:
  1409. ThisConnection - connection to act on.
  1410. Buffer - pointer of the buffer to free. Must be freed using
  1411. RpcFreeBuffer/I_RpcTransConnectionFreePacket
  1412. Return Value:
  1413. RPC_S_OK - the last buffer to free was accepted by the transport
  1414. RPC_S_CANNOT_SUPPORT - the transport does not support this functionality
  1415. --*/
  1416. {
  1417. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  1418. HTTP2ServerVirtualConnection *VirtualConnection;
  1419. RPC_STATUS RpcStatus;
  1420. if (BaseObject->id == HTTPv2)
  1421. {
  1422. // this must be called on server connections only
  1423. ASSERT(BaseObject->type == (COMPLEX_T | CONNECTION | SERVER));
  1424. VirtualConnection = (HTTP2ServerVirtualConnection *) ThisConnection;
  1425. VirtualConnection->SetLastBufferToFree(Buffer);
  1426. return RPC_S_OK;
  1427. }
  1428. else
  1429. {
  1430. return RPC_S_CANNOT_SUPPORT;
  1431. }
  1432. }
  1433. RPC_STATUS
  1434. RPC_ENTRY
  1435. HTTP_Open (
  1436. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  1437. IN RPC_CHAR * ProtocolSequence,
  1438. IN RPC_CHAR * NetworkAddress,
  1439. IN RPC_CHAR * Endpoint,
  1440. IN RPC_CHAR * NetworkOptions,
  1441. IN UINT ConnTimeout,
  1442. IN UINT SendBufferSize,
  1443. IN UINT RecvBufferSize,
  1444. IN PVOID ResolverHint,
  1445. IN BOOL fHintInitialized,
  1446. IN ULONG CallTimeout,
  1447. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  1448. IN void *AdditionalCredentials OPTIONAL
  1449. )
  1450. /*++
  1451. Routine Description:
  1452. Opens a connection to a server.
  1453. Arguments:
  1454. ThisConnection - A place to store the connection
  1455. ProtocolSeqeunce - "ncacn_http"
  1456. NetworkAddress - The name of the server, either a dot address or DNS name
  1457. NetworkOptions - the http binding handle options (e.g. HttpProxy/RpcProxy)
  1458. ConnTimeout - See RpcMgmtSetComTimeout
  1459. 0 - Min
  1460. 5 - Default
  1461. 9 - Max
  1462. 10 - Infinite
  1463. SendBufferSize - ignored
  1464. RecvBufferSize - ignored
  1465. ResolverHint - pointer to the resolver hint object
  1466. fHintInitialized - non-zero if the ResolverHint points to previously
  1467. initialized memory. 0 otheriwse.
  1468. CallTimeout - call timeout in milliseconds
  1469. AdditionalTransportCredentialsType - the type of additional credentials that we were
  1470. given
  1471. AdditionalCredentials - additional credentials that we were given.
  1472. Return Value:
  1473. RPC_S_OK
  1474. RPC_S_OUT_OF_MEMORY
  1475. RPC_S_OUT_OF_RESOURCES
  1476. RPC_S_SERVER_UNAVAILABLE
  1477. RPC_S_INVALID_ENDPOINT_FORMAT
  1478. RPC_S_INVALID_NET_ADDR
  1479. --*/
  1480. {
  1481. HTTPResolverHint *Hint = (HTTPResolverHint *)ResolverHint;
  1482. char *RpcProxyPort = NULL;
  1483. char *HttpProxyPort = NULL;
  1484. BOOL NetworkAddressAllocated;
  1485. BOOL Result;
  1486. char PortString[20];
  1487. ULONG StringLength;
  1488. RPC_STATUS Status;
  1489. RPC_STATUS RetValue;
  1490. PWS_CCONNECTION p = (PWS_CCONNECTION) ThisConnection;
  1491. HTTP2ClientVirtualConnection *VirtualConnection = (HTTP2ClientVirtualConnection *) ThisConnection;
  1492. BOOL Retry;
  1493. BOOL fUserModeConnection;
  1494. BOOL HintNeedsCleanup;
  1495. RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;
  1496. BOOL UseSSLPort;
  1497. ULONG HostAddr;
  1498. BOOL LocalDirect;
  1499. ASSERT(NetworkAddress);
  1500. ASSERT(Endpoint);
  1501. ASSERT(RpcpStringCompare(ProtocolSequence, L"ncacn_http") == 0);
  1502. if (AdditionalTransportCredentialsType != 0)
  1503. {
  1504. if (AdditionalTransportCredentialsType != RPC_C_AUTHN_INFO_TYPE_HTTP)
  1505. {
  1506. ASSERT(0);
  1507. return RPC_S_CANNOT_SUPPORT;
  1508. }
  1509. ASSERT(AdditionalCredentials != NULL);
  1510. }
  1511. HttpCredentials = (RPC_HTTP_TRANSPORT_CREDENTIALS_W *) AdditionalCredentials;
  1512. Status = InitializeHttpClientIfNecessary();
  1513. if (Status != RPC_S_OK)
  1514. return Status;
  1515. HintNeedsCleanup = FALSE;
  1516. // Check the resolver hint. If not initialized, initialize all
  1517. // fields in the hint
  1518. if (fHintInitialized == FALSE)
  1519. {
  1520. RpcProxyPort = NULL;
  1521. HttpProxyPort = NULL;
  1522. Hint->HTTPProxy = NULL;
  1523. Hint->RpcProxy = NULL;
  1524. Hint->RpcServer = NULL;
  1525. Status = Hint->AssociationGroupId.Create();
  1526. if (Status != RPC_S_OK)
  1527. {
  1528. RetValue = Status;
  1529. goto AbortAndCleanup;
  1530. }
  1531. // the TCP transport should have been initialized by now
  1532. ASSERT(HTTPTransInfo);
  1533. Status = HTTPTransInfo->StartServerIfNecessary();
  1534. if (Status != RPC_S_OK)
  1535. {
  1536. RetValue = Status;
  1537. goto AbortAndCleanup;
  1538. }
  1539. StringLength = RpcpStringLength(NetworkAddress);
  1540. //
  1541. // RPC Server Name
  1542. //
  1543. if (StringLength == 0)
  1544. {
  1545. // no server name was specified. Use local machine name
  1546. NetworkAddress = AllocateAndGetComputerName(cnaNew,
  1547. ComputerNamePhysicalDnsFullyQualified,
  1548. 0, // ExtraBytes
  1549. 0, // Starting offset
  1550. &StringLength
  1551. );
  1552. if (NetworkAddress == NULL)
  1553. return RPC_S_OUT_OF_MEMORY;
  1554. NetworkAddressAllocated = TRUE;
  1555. }
  1556. else
  1557. {
  1558. // make space for terminating NULL
  1559. StringLength += 1;
  1560. NetworkAddressAllocated = FALSE;
  1561. }
  1562. // StringLength is in characters and includes terminating null
  1563. if (StringLength <= sizeof(Hint->RpcServerName))
  1564. {
  1565. Hint->RpcServer = Hint->RpcServerName;
  1566. }
  1567. else
  1568. {
  1569. Hint->RpcServer = new char [StringLength];
  1570. if (Hint->RpcServer == NULL)
  1571. {
  1572. if (NetworkAddressAllocated)
  1573. delete NetworkAddress;
  1574. return RPC_S_OUT_OF_MEMORY;
  1575. }
  1576. }
  1577. SimplePlatformToAnsi(NetworkAddress, Hint->RpcServer);
  1578. // subtract 1 to eliminate terminating NULL
  1579. Hint->ServerNameLength = StringLength - 1;
  1580. if (NetworkAddressAllocated)
  1581. {
  1582. delete NetworkAddress;
  1583. NetworkAddress = NULL;
  1584. }
  1585. // by now Hint->RpcServer points to the ascii name for the server
  1586. ASSERT(Hint->RpcServer);
  1587. //
  1588. // At this point, we know the destination server/port, but don't yet know
  1589. // if we need to go through an HTTP proxy, and what the IIS RPC proxy
  1590. // machine is. We'll get these, if specified from the network options
  1591. // and the registry.
  1592. //
  1593. if (HttpCredentials && (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL))
  1594. UseSSLPort = TRUE;
  1595. else
  1596. UseSSLPort = FALSE;
  1597. Result = HttpParseNetworkOptions(
  1598. NetworkOptions,
  1599. Hint->RpcServer,
  1600. &(Hint->RpcProxy),
  1601. &RpcProxyPort,
  1602. UseSSLPort,
  1603. &(Hint->HTTPProxy),
  1604. &HttpProxyPort,
  1605. &(Hint->AccessType),
  1606. (unsigned long *) &Status
  1607. );
  1608. if (Result == FALSE)
  1609. {
  1610. ASSERT(Status != RPC_S_OK);
  1611. Hint->FreeRpcServer();
  1612. return Status;
  1613. }
  1614. else
  1615. {
  1616. if (Hint->AccessType != rpcpatDirect)
  1617. {
  1618. ASSERT(Hint->HTTPProxy);
  1619. // if the proxy name is empty, set the method to direct
  1620. if (Hint->HTTPProxy[0] == 0)
  1621. Hint->AccessType = rpcpatDirect;
  1622. }
  1623. ASSERT(Status == RPC_S_OK);
  1624. HintNeedsCleanup = TRUE;
  1625. }
  1626. Status = EndpointToPortNumber(Endpoint, Hint->ServerPort);
  1627. if (Status != RPC_S_OK)
  1628. {
  1629. RetValue = Status;
  1630. goto AbortAndCleanup;
  1631. }
  1632. Status = EndpointToPortNumberA(RpcProxyPort, Hint->RpcProxyPort);
  1633. if (Status != RPC_S_OK)
  1634. {
  1635. RetValue = Status;
  1636. goto AbortAndCleanup;
  1637. }
  1638. Hint->ProxyNameLength = RpcpStringLengthA(Hint->RpcProxy);
  1639. if (Hint->HTTPProxy)
  1640. {
  1641. Status = EndpointToPortNumberA(HttpProxyPort, Hint->HTTPProxyPort);
  1642. if (Status != RPC_S_OK)
  1643. {
  1644. RetValue = Status;
  1645. goto AbortAndCleanup;
  1646. }
  1647. }
  1648. // we will optimistically presume that we can talk HTTP2
  1649. // until proven wrong
  1650. Hint->Version = httpvHTTP2;
  1651. // by now the resolver hint is fully initialized. fall through
  1652. // the case that has initialized resolver hint
  1653. }
  1654. Hint->VerifyInitialized();
  1655. // disable retries by default. If we have to loop around, we will set it to TRUE
  1656. Retry = FALSE;
  1657. do
  1658. {
  1659. // we have it all now.
  1660. if (Hint->Version == httpvHTTP2)
  1661. {
  1662. // use explicit placement
  1663. VirtualConnection = new (ThisConnection) HTTP2ClientVirtualConnection (
  1664. (RPC_HTTP_TRANSPORT_CREDENTIALS *)AdditionalCredentials,
  1665. &Status);
  1666. if (Status != RPC_S_OK)
  1667. {
  1668. VirtualConnection->HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  1669. RetValue = Status;
  1670. goto AbortAndCleanup;
  1671. }
  1672. Status = VirtualConnection->ClientOpen(Hint,
  1673. fHintInitialized,
  1674. ConnTimeout,
  1675. CallTimeout
  1676. );
  1677. // if we got a protocol error or a receive failed, and
  1678. // we don't have credentials, fall back to old protocol.
  1679. if (
  1680. (
  1681. (Status == RPC_S_PROTOCOL_ERROR)
  1682. ||
  1683. (Status == RPC_P_RECEIVE_FAILED)
  1684. )
  1685. &&
  1686. (HttpCredentials == NULL)
  1687. )
  1688. {
  1689. // cause the loop to start over.
  1690. // make sure next iteration it tries old http
  1691. Hint->Version = httpvHTTP;
  1692. VirtualConnection->HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  1693. Retry = TRUE;
  1694. }
  1695. else
  1696. {
  1697. if ((Status == RPC_S_PROTOCOL_ERROR)
  1698. ||
  1699. (Status == RPC_P_RECEIVE_FAILED))
  1700. {
  1701. Status = RPC_S_SERVER_UNAVAILABLE;
  1702. }
  1703. ASSERT(Status != RPC_P_PACKET_CONSUMED);
  1704. RetValue = Status;
  1705. VirtualConnection->id = HTTPv2;
  1706. if (Status == RPC_S_OK)
  1707. goto CleanupAndExit;
  1708. else
  1709. {
  1710. VirtualConnection->HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  1711. goto AbortAndCleanup;
  1712. }
  1713. }
  1714. }
  1715. else
  1716. {
  1717. ASSERT(Hint->Version == httpvHTTP);
  1718. // HTTP1 doesn't support proxy discovery. If we don't know
  1719. // just assume local and hope it works.
  1720. if (Hint->AccessType == rpcpatUnknown)
  1721. Hint->AccessType = rpcpatDirect;
  1722. // we need to re-initialize the connection object with old
  1723. // format connection
  1724. WS_Initialize(p, 0, 0, 0);
  1725. // use explicit placement to initialize the vtable. We need this to
  1726. // be able to use the virtual functions
  1727. p = new (p) WS_CLIENT_CONNECTION;
  1728. p->id = HTTP;
  1729. // Call common open function. Note that for http connection
  1730. // WS_Open will just open a socket. That's all we need right now.
  1731. Status = WS_Open(p,
  1732. NULL,
  1733. ConnTimeout,
  1734. SendBufferSize,
  1735. RecvBufferSize,
  1736. CallTimeout,
  1737. FALSE // fHTTP2Open
  1738. );
  1739. if (Status != RPC_S_OK)
  1740. {
  1741. RetValue = Status;
  1742. goto AbortAndCleanup;
  1743. }
  1744. //
  1745. // WS_Open has been successfully called. Do connect() work here...
  1746. //
  1747. // If AccessType is direct, then we are going to try to directly
  1748. // connect to the IIS that is the RPC Proxy first. If that suceeds,
  1749. // then we will just tunnel to the RPC server from there. If it fails,
  1750. // then we will try to go through an HTTP proxy (i.e. MSProxy server)
  1751. // if one is available...
  1752. if (Hint->AccessType != rpcpatHTTPProxy)
  1753. {
  1754. Status = HTTP_CheckIPAddressForDirectConnection(Hint);
  1755. if (Status != RPC_S_OK)
  1756. {
  1757. RetValue = RPC_S_OUT_OF_MEMORY;
  1758. goto AbortAndCleanup;
  1759. }
  1760. if (Hint->AccessType == rpcpatDirect)
  1761. {
  1762. Status = HTTP_TryConnect( p->Conn.Socket, Hint->RpcProxy, Hint->RpcProxyPort );
  1763. }
  1764. }
  1765. if ((Status != RPC_S_OK) || (Hint->AccessType != rpcpatDirect))
  1766. {
  1767. //
  1768. // If we get here, then we are going to try to use an HTTP proxy first...
  1769. //
  1770. Status = HTTP_TryConnect( p->Conn.Socket, Hint->HTTPProxy, Hint->HTTPProxyPort );
  1771. //
  1772. // If we successfully connected to the HTTP proxy, then let's go on and
  1773. // tunnel through to the RPC proxy:
  1774. //
  1775. if (Status != RPC_S_OK)
  1776. {
  1777. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1778. goto Abort;
  1779. }
  1780. PortNumberToEndpointA(Hint->RpcProxyPort, PortString);
  1781. if (!HttpTunnelToRpcProxy(p->Conn.Socket,
  1782. Hint->RpcProxy,
  1783. PortString))
  1784. {
  1785. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1786. goto Abort;
  1787. }
  1788. }
  1789. //
  1790. // Finally, negotiate with the RPC proxy to get the connection through to
  1791. // the RPC server.
  1792. //
  1793. PortNumberToEndpointA(Hint->ServerPort, PortString);
  1794. if (!HttpTunnelToRpcServer( p->Conn.Socket,
  1795. Hint->RpcServer,
  1796. PortString ))
  1797. {
  1798. RetValue = RPC_S_SERVER_UNAVAILABLE;
  1799. goto Abort;
  1800. }
  1801. fUserModeConnection = IsUserModeSocket(p->Conn.Socket, &RetValue);
  1802. if (RetValue != RPC_S_OK)
  1803. goto Abort;
  1804. // if this is SAN or loadable transport not using true handles, go through Winsock
  1805. if (fUserModeConnection)
  1806. p = new (p) WS_SAN_CLIENT_CONNECTION;
  1807. Retry = FALSE;
  1808. }
  1809. }
  1810. while (Retry);
  1811. RetValue = RPC_S_OK;
  1812. goto CleanupAndExit;
  1813. Abort:
  1814. p->WS_CONNECTION::Abort();
  1815. AbortAndCleanup:
  1816. if (HintNeedsCleanup)
  1817. {
  1818. ASSERT(RetValue != RPC_S_OK);
  1819. Hint->FreeRpcServer();
  1820. Hint->FreeRpcProxy();
  1821. Hint->FreeHTTPProxy();
  1822. }
  1823. CleanupAndExit:
  1824. // Creating a thread can fail with RPC_S_OUT_OF_THREADS
  1825. // and the caller may not be prepared to deal with this error.
  1826. if (RetValue == RPC_S_OUT_OF_THREADS)
  1827. {
  1828. RetValue = RPC_S_OUT_OF_RESOURCES;
  1829. }
  1830. VALIDATE (RetValue)
  1831. {
  1832. RPC_S_OK,
  1833. RPC_S_PROTSEQ_NOT_SUPPORTED,
  1834. RPC_S_SERVER_UNAVAILABLE,
  1835. RPC_S_OUT_OF_MEMORY,
  1836. RPC_S_OUT_OF_RESOURCES,
  1837. RPC_S_SERVER_TOO_BUSY,
  1838. RPC_S_INVALID_NETWORK_OPTIONS,
  1839. RPC_S_INVALID_ENDPOINT_FORMAT,
  1840. RPC_S_INVALID_NET_ADDR,
  1841. RPC_S_ACCESS_DENIED,
  1842. RPC_S_INTERNAL_ERROR,
  1843. RPC_S_SERVER_OUT_OF_MEMORY,
  1844. RPC_S_CALL_CANCELLED
  1845. } END_VALIDATE;
  1846. if (RpcProxyPort != NULL)
  1847. delete RpcProxyPort;
  1848. if (HttpProxyPort != NULL)
  1849. delete HttpProxyPort;
  1850. if (Hint->ServerNameLength <= sizeof(Hint->RpcServerName))
  1851. {
  1852. ASSERT(Hint->RpcServer == Hint->RpcServerName);
  1853. }
  1854. return (RetValue);
  1855. }
  1856. RPC_STATUS
  1857. HTTP_ServerListen(
  1858. IN RPC_TRANSPORT_ADDRESS ThisAddress,
  1859. IN RPC_CHAR *NetworkAddress,
  1860. IN OUT RPC_CHAR * *pEndpoint,
  1861. IN UINT PendingQueueSize,
  1862. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1863. IN ULONG EndpointFlags,
  1864. IN ULONG NICFlags
  1865. )
  1866. {
  1867. RPC_STATUS RpcStatus;
  1868. RpcStatus = InitializeHttpServerIfNecessary();
  1869. if (RpcStatus != RPC_S_OK)
  1870. return RpcStatus;
  1871. return (TCP_ServerListenEx(
  1872. ThisAddress,
  1873. NetworkAddress,
  1874. pEndpoint,
  1875. PendingQueueSize,
  1876. SecurityDescriptor,
  1877. EndpointFlags,
  1878. NICFlags,
  1879. TRUE // HTTP!
  1880. ));
  1881. }
  1882. void WINAPI ProxyIoCompletionCallback (
  1883. IN LPEXTENSION_CONTROL_BLOCK lpECB,
  1884. IN PVOID pContext,
  1885. IN DWORD cbIO,
  1886. IN DWORD dwError
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. IIS io completion callback function
  1891. Arguments:
  1892. lpECB - extension control block
  1893. pContext - the IISChannel pointer.
  1894. cbIO - Bytes transferred in the last operation
  1895. dwError - status of the operation
  1896. Return Value:
  1897. --*/
  1898. {
  1899. HTTP2IISTransportChannel *IISChannel;
  1900. THREAD *Thread;
  1901. Thread = ThreadSelf();
  1902. if (Thread == NULL)
  1903. return; // abandon the completion if worse comes to worse.
  1904. IISChannel = (HTTP2IISTransportChannel *)pContext;
  1905. IISChannel->IOCompleted(cbIO, dwError);
  1906. }
  1907. BOOL RPCTransInitialized = FALSE;
  1908. RPCRTAPI
  1909. RPC_STATUS
  1910. RPC_ENTRY
  1911. I_RpcProxyNewConnection (
  1912. IN ULONG ConnectionType,
  1913. IN USHORT *ServerAddress,
  1914. IN USHORT *ServerPort,
  1915. IN void *ConnectionParameter,
  1916. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface
  1917. )
  1918. /*++
  1919. Routine Description:
  1920. Entry point from the ISAPI extension. Called when a new
  1921. connection request arrives at an in or out proxy.
  1922. Arguments:
  1923. ConnectionType - currently RPC_PROXY_CONNECTION_TYPE_IN_PROXY or
  1924. RPC_PROXY_CONNECTION_TYPE_OUT_PROXY to indicate the type of
  1925. connection establishment request we have received
  1926. ServerAddress - unicode network address of the server
  1927. ServerPort - unicode port of the server
  1928. ConnectionParameter - the Extension Control Block in this case.
  1929. ProxyCallbackInterface - a callback interface to the proxy to perform
  1930. various proxy specific functions
  1931. Return Value:
  1932. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  1933. Note:
  1934. This function and all its callees must ensure that if this function
  1935. returns error, it doesn't call HSE_REQ_DONE_WITH_SESSION. If it
  1936. return RPC_S_OK, it must call HSE_REQ_DONE_WITH_SESSION. If these 2
  1937. rules are violated, IIS will AV.
  1938. --*/
  1939. {
  1940. RPC_STATUS RpcStatus = RPC_S_OK;
  1941. EXTENSION_CONTROL_BLOCK *ECB;
  1942. void *IISContext;
  1943. BOOL Result;
  1944. RPC_TRANSPORT_INTERFACE TransInterface;
  1945. TRANS_INFO *TransInfo;
  1946. THREAD *ThisThread;
  1947. HTTP2ProxyVirtualConnection *ProxyVirtualConnection;
  1948. if (RPCTransInitialized == FALSE)
  1949. {
  1950. InitializeIfNecessary();
  1951. GlobalMutexRequest();
  1952. // all of the initialization here is idempotent.
  1953. // If we fail midway, we don't have to un-initialize -
  1954. // next initialization attempt will pick up where we left.
  1955. RpcStatus = OsfMapRpcProtocolSequence(FALSE,
  1956. L"ncacn_http",
  1957. &TransInfo);
  1958. if (RpcStatus == RPC_S_OK)
  1959. {
  1960. ASSERT(TransInfo);
  1961. if (HTTPTransInfo == NULL)
  1962. HTTPTransInfo = TransInfo;
  1963. RpcStatus = TransInfo->StartServerIfNecessary();
  1964. if (RpcStatus == RPC_S_OK)
  1965. {
  1966. RpcStatus = InitializeDefaultChannelLifetime();
  1967. if (RpcStatus == RPC_S_OK)
  1968. {
  1969. RpcStatus = InitializeActAsWebFarm();
  1970. if (RpcStatus == RPC_S_OK)
  1971. {
  1972. RpcStatus = InitializeMinConnectionTimeout();
  1973. if (RpcStatus == RPC_S_OK)
  1974. {
  1975. RpcStatus = CookieCollection::InitializeInProxyCookieCollection();
  1976. if (RpcStatus == RPC_S_OK)
  1977. {
  1978. RpcStatus = CookieCollection::InitializeOutProxyCookieCollection();
  1979. if (RpcStatus == RPC_S_OK)
  1980. {
  1981. RpcStatus = InitializeReceiveWindows();
  1982. }
  1983. }
  1984. }
  1985. }
  1986. }
  1987. }
  1988. }
  1989. RPCTransInitialized = (RpcStatus == RPC_S_OK);
  1990. GlobalMutexClear();
  1991. if (RpcStatus != RPC_S_OK)
  1992. {
  1993. return RPC_S_OK;
  1994. }
  1995. }
  1996. ThisThread = ThreadSelf();
  1997. if (ThisThread == NULL)
  1998. return RPC_S_OUT_OF_MEMORY;
  1999. if (ConnectionType == RPC_PROXY_CONNECTION_TYPE_IN_PROXY)
  2000. {
  2001. ProxyVirtualConnection = new HTTP2InProxyVirtualConnection(&RpcStatus);
  2002. }
  2003. else
  2004. {
  2005. ASSERT(ConnectionType == RPC_PROXY_CONNECTION_TYPE_OUT_PROXY);
  2006. ProxyVirtualConnection = new HTTP2OutProxyVirtualConnection(&RpcStatus);
  2007. }
  2008. if (ProxyVirtualConnection == NULL)
  2009. return RPC_S_OUT_OF_MEMORY;
  2010. if (RpcStatus != RPC_S_OK)
  2011. {
  2012. delete ProxyVirtualConnection;
  2013. return RpcStatus;
  2014. }
  2015. RpcStatus = ProxyVirtualConnection->InitializeProxyFirstLeg(ServerAddress,
  2016. ServerPort,
  2017. ConnectionParameter,
  2018. ProxyCallbackInterface,
  2019. &IISContext
  2020. );
  2021. if (RpcStatus != RPC_S_OK)
  2022. {
  2023. delete ProxyVirtualConnection;
  2024. return RpcStatus;
  2025. }
  2026. // we have initialized far enough. Associate callback
  2027. // with this connection
  2028. ECB = (EXTENSION_CONTROL_BLOCK *) ConnectionParameter;
  2029. Result = ECB->ServerSupportFunction (ECB->ConnID,
  2030. HSE_REQ_IO_COMPLETION,
  2031. ProxyIoCompletionCallback,
  2032. NULL,
  2033. (LPDWORD)IISContext
  2034. );
  2035. if (Result == FALSE)
  2036. {
  2037. ProxyVirtualConnection->Abort();
  2038. return RPC_S_OUT_OF_MEMORY;
  2039. }
  2040. // after we call StartProxy, it takes off on success and
  2041. // we don't know whether we have a vconnection anymore. Thus
  2042. // we must block rundowns until we are done with everything.
  2043. ProxyVirtualConnection->BlockConnectionFromRundown();
  2044. RpcStatus = ProxyVirtualConnection->StartProxy();
  2045. if (RpcStatus != RPC_S_OK)
  2046. {
  2047. ProxyVirtualConnection->UnblockConnectionFromRundown();
  2048. ProxyVirtualConnection->Abort();
  2049. return RpcStatus;
  2050. }
  2051. ProxyVirtualConnection->EnableIISSessionClose();
  2052. ProxyVirtualConnection->UnblockConnectionFromRundown();
  2053. return RpcStatus;
  2054. }
  2055. RPCRTAPI
  2056. RPC_STATUS
  2057. RPC_ENTRY
  2058. HTTP2IISDirectReceive (
  2059. IN void *Context
  2060. )
  2061. /*++
  2062. Routine Description:
  2063. Direct notification from the thread pool to an IIS channel
  2064. for a receive. The proxy stacks use that to post receives
  2065. to themselves.
  2066. Arguments:
  2067. Context - the HTTP2IISTransportChannel
  2068. Return Value:
  2069. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2070. --*/
  2071. {
  2072. ((HTTP2IISTransportChannel *)Context)->DirectReceive();
  2073. return RPC_S_OK;
  2074. }
  2075. RPCRTAPI
  2076. RPC_STATUS
  2077. RPC_ENTRY
  2078. HTTP2DirectReceive (
  2079. IN void *Context,
  2080. OUT BYTE **ReceivedBuffer,
  2081. OUT ULONG *ReceivedBufferLength,
  2082. OUT void **RuntimeConnection,
  2083. OUT BOOL *IsServer
  2084. )
  2085. /*++
  2086. Routine Description:
  2087. Direct notification from the thread pool to a receiver
  2088. for a receive. The stacks use that to post receives
  2089. to themselves.
  2090. Arguments:
  2091. Context - an instance of the HTTP2EndpointReceiver
  2092. ReceivedBuffer - the buffer that we received.
  2093. ReceivedBufferLength - the length of the received
  2094. buffer
  2095. RuntimeConnection - the connection to return to the runtime
  2096. if the packet is not consumed.
  2097. IsServer - true if this is the server
  2098. Return Value:
  2099. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2100. --*/
  2101. {
  2102. RPC_STATUS RpcStatus;
  2103. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_RECV_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2104. RpcStatus = ((HTTP2EndpointReceiver *)Context)->DirectReceiveComplete(
  2105. ReceivedBuffer,
  2106. ReceivedBufferLength,
  2107. RuntimeConnection,
  2108. IsServer
  2109. );
  2110. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_RECV_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2111. return RpcStatus;
  2112. }
  2113. RPCRTAPI
  2114. RPC_STATUS
  2115. RPC_ENTRY
  2116. HTTP2WinHttpDirectReceive (
  2117. IN void *Context,
  2118. OUT BYTE **ReceivedBuffer,
  2119. OUT ULONG *ReceivedBufferLength,
  2120. OUT void **RuntimeConnection
  2121. )
  2122. /*++
  2123. Routine Description:
  2124. Direct notification from the thread pool to a receiver
  2125. for a receive. The stacks use that to post receives
  2126. to themselves.
  2127. Arguments:
  2128. Context - an instance of HTTP2WinHttpTransportChannel
  2129. ReceivedBuffer - the buffer that we received.
  2130. ReceivedBufferLength - the length of the received
  2131. buffer
  2132. RuntimeConnection - the connection to return to the runtime
  2133. if the packet is not consumed.
  2134. Return Value:
  2135. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2136. --*/
  2137. {
  2138. RPC_STATUS RpcStatus;
  2139. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DRECV_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2140. RpcStatus = ((HTTP2WinHttpTransportChannel *)Context)->DirectReceiveComplete(
  2141. ReceivedBuffer,
  2142. ReceivedBufferLength,
  2143. RuntimeConnection
  2144. );
  2145. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DRECV_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2146. return RpcStatus;
  2147. }
  2148. RPCRTAPI
  2149. RPC_STATUS
  2150. RPC_ENTRY
  2151. HTTP2WinHttpDirectSend (
  2152. IN void *Context,
  2153. OUT BYTE **SentBuffer,
  2154. OUT void **SendContext
  2155. )
  2156. /*++
  2157. Routine Description:
  2158. Direct notification from the thread pool to a sender
  2159. for a send. The stacks use that to post sends
  2160. to themselves.
  2161. Arguments:
  2162. Context - an instance of HTTP2WinHttpTransportChannel
  2163. SentBuffer - the buffer that we sent.
  2164. SendContext - the send context to return to the runtime
  2165. if the packet is not consumed.
  2166. Return Value:
  2167. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2168. --*/
  2169. {
  2170. RPC_STATUS RpcStatus;
  2171. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DSEND_COMPLETE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)Context);
  2172. RpcStatus = ((HTTP2WinHttpTransportChannel *)Context)->DirectSendComplete(
  2173. SentBuffer,
  2174. SendContext
  2175. );
  2176. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DSEND_COMPLETE, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2177. return RpcStatus;
  2178. }
  2179. RPCRTAPI
  2180. void
  2181. RPC_ENTRY
  2182. HTTP2WinHttpDelayedReceive (
  2183. IN void *Context
  2184. )
  2185. /*++
  2186. Routine Description:
  2187. Direct notification from the thread pool to
  2188. post a DelayedReceive.
  2189. Arguments:
  2190. Context - an instance of HTTP2WinHttpTransportChannel
  2191. Return Value:
  2192. none
  2193. --*/
  2194. {
  2195. ((HTTP2WinHttpTransportChannel *)Context)->DelayedReceive();
  2196. }
  2197. RPCRTAPI
  2198. RPC_STATUS
  2199. RPC_ENTRY
  2200. HTTP2PlugChannelDirectSend (
  2201. IN void *Context
  2202. )
  2203. /*++
  2204. Routine Description:
  2205. Direct notification from the thread pool to the plug channel
  2206. for a send. The plug channel uses that to post sends
  2207. to itself. Usable only on proxies (i.e. doesn't return to runtime)
  2208. Arguments:
  2209. Context - an instance of HTTP2PlugChannel
  2210. Return Value:
  2211. RPC_S_OK
  2212. --*/
  2213. {
  2214. return ((HTTP2PlugChannel *)Context)->DirectSendComplete();
  2215. }
  2216. RPCRTAPI
  2217. RPC_STATUS
  2218. RPC_ENTRY
  2219. HTTP2FlowControlChannelDirectSend (
  2220. IN void *Context,
  2221. OUT BOOL *IsServer,
  2222. OUT BOOL *SendToRuntime,
  2223. OUT void **SendContext,
  2224. OUT BUFFER *Buffer,
  2225. OUT UINT *BufferLength
  2226. )
  2227. /*++
  2228. Routine Description:
  2229. Direct notification from the thread pool to the flow control channel
  2230. for a send. The flow control channel uses that to post sends
  2231. to itself.
  2232. Arguments:
  2233. Context - an instance of HTTP2FlowControlSender
  2234. IsServer - on both success and failure MUST be set by this function.
  2235. SendToRuntime - on both success and failure MUST be set by this function.
  2236. SendContext - the send context as needs to be seen by the runtime
  2237. Buffer - on output the buffer that we tried to send
  2238. BufferLength - on output the length of the buffer we tried to send
  2239. Return Value:
  2240. RPC_S_OK
  2241. --*/
  2242. {
  2243. RPC_STATUS RpcStatus;
  2244. #if DBG
  2245. *IsServer = 0xBAADBAAD;
  2246. *SendToRuntime = 0xBAADBAAD;
  2247. #endif // DBG
  2248. RpcStatus = ((HTTP2FlowControlSender *)Context)->DirectSendComplete(IsServer,
  2249. SendToRuntime,
  2250. SendContext,
  2251. Buffer,
  2252. BufferLength);
  2253. // make sure DirectSendComplete didn't forget to set it
  2254. ASSERT(*IsServer != 0xBAADBAAD);
  2255. ASSERT(*SendToRuntime != 0xBAADBAAD);
  2256. return RpcStatus;
  2257. }
  2258. RPCRTAPI
  2259. RPC_STATUS
  2260. RPC_ENTRY
  2261. HTTP2ChannelDataOriginatorDirectSend (
  2262. IN void *Context,
  2263. OUT BOOL *IsServer,
  2264. OUT void **SendContext,
  2265. OUT BUFFER *Buffer,
  2266. OUT UINT *BufferLength
  2267. )
  2268. /*++
  2269. Routine Description:
  2270. Direct notification from the thread pool to the channel data originator
  2271. for a send complete. The channel data originator uses that to post send
  2272. compeltes to itself. Usable only on endpoints (i.e. does return to runtime)
  2273. Arguments:
  2274. Context - an instance of HTTP2ChannelDataOriginator
  2275. IsServer - on both success and failure MUST be set by this function.
  2276. SendContext - the send context as needs to be seen by the runtime
  2277. Buffer - on output the buffer that we tried to send
  2278. BufferLength - on output the length of the buffer we tried to send
  2279. Return Value:
  2280. RPC_S_OK
  2281. --*/
  2282. {
  2283. RPC_STATUS RpcStatus;
  2284. #if DBG
  2285. *IsServer = 0xBAADBAAD;
  2286. #endif // DBG
  2287. RpcStatus = ((HTTP2ChannelDataOriginator *)Context)->DirectSendComplete(IsServer,
  2288. SendContext,
  2289. Buffer,
  2290. BufferLength);
  2291. // make sure DirectSendComplete didn't forget to set it
  2292. ASSERT(*IsServer != 0xBAADBAAD);
  2293. return RpcStatus;
  2294. }
  2295. RPCRTAPI
  2296. void
  2297. RPC_ENTRY
  2298. HTTP2TimerReschedule (
  2299. IN void *Context
  2300. )
  2301. /*++
  2302. Routine Description:
  2303. A timer reschedule notification came in.
  2304. Arguments:
  2305. Context - actually a ping channel pointer for the channel
  2306. that asked for rescheduling
  2307. Return Value:
  2308. --*/
  2309. {
  2310. HTTP2PingOriginator *PingChannel;
  2311. PingChannel = (HTTP2PingOriginator *)Context;
  2312. PingChannel->RescheduleTimer();
  2313. }
  2314. RPCRTAPI
  2315. void
  2316. RPC_ENTRY
  2317. HTTP2AbortConnection (
  2318. IN void *Context
  2319. )
  2320. /*++
  2321. Routine Description:
  2322. A request to abort the connection was posted on a worker thread.
  2323. Arguments:
  2324. Context - actually a top channel pointer for the connection to abort.
  2325. Return Value:
  2326. --*/
  2327. {
  2328. HTTP2Channel *TopChannel;
  2329. TopChannel = (HTTP2Channel *)Context;
  2330. TopChannel->AbortConnection(RPC_P_CONNECTION_SHUTDOWN);
  2331. TopChannel->RemoveReference();
  2332. }
  2333. RPCRTAPI
  2334. void
  2335. RPC_ENTRY
  2336. HTTP2RecycleChannel (
  2337. IN void *Context
  2338. )
  2339. /*++
  2340. Routine Description:
  2341. A request to recycle the channel was posted on a worker thread.
  2342. Arguments:
  2343. Context - actually a top channel pointer for the channel to
  2344. recycle.
  2345. Return Value:
  2346. --*/
  2347. {
  2348. HTTP2Channel *TopChannel;
  2349. TopChannel = (HTTP2Channel *)Context;
  2350. // don't care about return code. See rule 29.
  2351. (void) TopChannel->HandleSendResultFromNeutralContext(RPC_P_CHANNEL_NEEDS_RECYCLING);
  2352. TopChannel->RemoveReference();
  2353. }
  2354. RPC_STATUS
  2355. HTTP2ProcessComplexTReceive (
  2356. IN OUT void **Connection,
  2357. IN RPC_STATUS EventStatus,
  2358. IN ULONG Bytes,
  2359. OUT BUFFER *Buffer,
  2360. OUT UINT *BufferLength
  2361. )
  2362. /*++
  2363. Routine Description:
  2364. A receive notification came from the completion port.
  2365. Arguments:
  2366. Connection - a pointer to a pointer to a connection.
  2367. On input it will be the raw connection. On output
  2368. it needs to be the virtual connection so that
  2369. runtime can find its object off there. This out
  2370. parameter must be set on both success and failure.
  2371. EventStatus - status of the operation
  2372. Bytes - bytes received
  2373. Buffer - on output (success only), the received buffer
  2374. BufferLength - on output (success only), the length of the
  2375. received buffer.
  2376. Return Value:
  2377. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2378. RPC_P_PARTIAL_RECEIVE allowed for partial receives.
  2379. RPC_P_PACKET_CONSUMED must be returned for all transport
  2380. traffic (success or failure). Anything else will AV the
  2381. runtime.
  2382. --*/
  2383. {
  2384. WS_HTTP2_CONNECTION *RawConnection = (WS_HTTP2_CONNECTION *)*Connection;
  2385. BYTE *Packet;
  2386. ULONG PacketLength;
  2387. WS_HTTP2_INITIAL_CONNECTION *ThisConnection;
  2388. HTTP2ServerVirtualConnection *ServerVirtualConnection;
  2389. BOOL VirtualConnectionCreated;
  2390. LOG_FN_OPERATION_ENTRY(HTTP2LOG_COMPLEX_T_RECV, HTTP2LOG_OT_CALLBACK, EventStatus);
  2391. ASSERT (EventStatus != RPC_P_PACKET_CONSUMED);
  2392. // Detect whether this is an initial connection.
  2393. // If this is an initial connection, process receive and initialize the connection.
  2394. // EventStatus will be RPC_P_INITIALIZE_HTTP2_CONNECTION in the case of connection establishment.
  2395. if (EventStatus == RPC_P_INITIALIZE_HTTP2_CONNECTION)
  2396. {
  2397. Packet = (BYTE *) *Buffer;
  2398. PacketLength = *BufferLength;
  2399. ThisConnection = (WS_HTTP2_INITIAL_CONNECTION *) *Connection;
  2400. // The packet received must have been an RTS packet.
  2401. ASSERT(IsRTSPacket(Packet));
  2402. // unlink this connection from the PnP list before it is migrated
  2403. TransportProtocol::RemoveObjectFromProtocolList((BASE_ASYNC_OBJECT *) ThisConnection);
  2404. EventStatus = HTTP2ServerVirtualConnection::InitializeServerConnection (
  2405. Packet,
  2406. PacketLength,
  2407. ThisConnection,
  2408. &ServerVirtualConnection,
  2409. &VirtualConnectionCreated
  2410. );
  2411. // Note that if the above call succeeds, ThisConnection may have been deleted on another thread
  2412. // after this point. This is possible when the data receive posted has completed on another thread,
  2413. // causing a connection close.
  2414. if (EventStatus == RPC_S_OK)
  2415. {
  2416. // We are done with connection initialization and may return.
  2417. // N.B. Do not use the this pointer as WS_HTTP2_INITIAL_CONNECTION
  2418. // pointer after here. It has been migrated to a new location
  2419. // and this actually points to HTTP2ServerVirtualConnection
  2420. *Buffer = NULL;
  2421. *BufferLength = 0;
  2422. RpcFreeBuffer(Packet);
  2423. return RPC_P_PACKET_CONSUMED;
  2424. }
  2425. else
  2426. {
  2427. if (VirtualConnectionCreated == FALSE)
  2428. {
  2429. // failed to create a virtual connection. Link the connection
  2430. // back to its protocol list to ensure orderly destruction
  2431. TransportProtocol::AddObjectToProtocolList((BASE_ASYNC_OBJECT *) ThisConnection);
  2432. // Send failure to the runtime to have the OSF_SCONNECTION cleaned up.
  2433. return RPC_P_RECEIVE_FAILED;
  2434. }
  2435. else
  2436. {
  2437. // nothing to do. The virtual connection was created but it failed to
  2438. // initialize. We will process the failure and let the runtime destroy
  2439. // the connection.
  2440. EventStatus = RPC_P_RECEIVE_FAILED;
  2441. }
  2442. }
  2443. // The only status expected beyond this point is a failure.
  2444. ASSERT(EventStatus == RPC_P_RECEIVE_FAILED);
  2445. }
  2446. // stick the runtime idea of the transport connection
  2447. *Connection = RawConnection->RuntimeConnectionPtr;
  2448. if (Bytes && (EventStatus == RPC_S_OK))
  2449. {
  2450. EventStatus = RawConnection->ProcessReceiveComplete(Bytes,
  2451. Buffer,
  2452. BufferLength);
  2453. if (EventStatus == RPC_P_PARTIAL_RECEIVE)
  2454. {
  2455. // Message is not complete, submit the next read and continue.
  2456. EventStatus = CO_SubmitRead(RawConnection);
  2457. if (EventStatus != RPC_S_OK)
  2458. {
  2459. EventStatus = RawConnection->ProcessReceiveFailed(RPC_P_CONNECTION_SHUTDOWN);
  2460. if (EventStatus != RPC_P_PACKET_CONSUMED)
  2461. {
  2462. ASSERT(EventStatus == RPC_P_RECEIVE_FAILED);
  2463. }
  2464. }
  2465. else
  2466. EventStatus = RPC_P_PARTIAL_RECEIVE;
  2467. }
  2468. else
  2469. {
  2470. ASSERT( (EventStatus == RPC_P_RECEIVE_FAILED)
  2471. || (EventStatus == RPC_S_OK)
  2472. || (EventStatus == RPC_P_PACKET_CONSUMED)
  2473. || (EventStatus == RPC_P_CONNECTION_CLOSED));
  2474. }
  2475. }
  2476. else
  2477. {
  2478. // in other rare case (again server connection establishment), the connection
  2479. // can be the virtual connection, not the transport connection. In such cases,
  2480. // let the error fall through back to the runtime. Since this happens only during
  2481. // connection establishment, and the receive did not go through the channels,
  2482. // we should not complete it through the channels.
  2483. if ((RawConnection->id == HTTPv2)
  2484. && (RawConnection->type == (COMPLEX_T | CONNECTION | SERVER)))
  2485. {
  2486. // this is a server virtual connecton. Read the connection from there
  2487. *Connection = RawConnection;
  2488. }
  2489. else
  2490. {
  2491. if (EventStatus != RPC_S_OK)
  2492. EventStatus = RawConnection->ProcessReceiveFailed(EventStatus);
  2493. else
  2494. EventStatus = RawConnection->ProcessReceiveFailed(RPC_P_RECEIVE_FAILED);
  2495. if (EventStatus == RPC_P_CONNECTION_SHUTDOWN)
  2496. EventStatus = RPC_P_RECEIVE_FAILED;
  2497. }
  2498. ASSERT( (EventStatus == RPC_P_RECEIVE_FAILED)
  2499. || (EventStatus == RPC_S_OK)
  2500. || (EventStatus == RPC_P_PACKET_CONSUMED));
  2501. }
  2502. LOG_FN_OPERATION_EXIT(HTTP2LOG_COMPLEX_T_RECV, HTTP2LOG_OT_CALLBACK, EventStatus);
  2503. return EventStatus;
  2504. }
  2505. RPC_STATUS
  2506. HTTP2ProcessComplexTSend (
  2507. IN void *SendContext,
  2508. IN RPC_STATUS EventStatus,
  2509. OUT BUFFER *Buffer
  2510. )
  2511. /*++
  2512. Routine Description:
  2513. A send notification came from the completion port.
  2514. Arguments:
  2515. SendContext - the send context
  2516. EventStatus - status of the operation
  2517. Buffer - if the packet is not consumed, must be the sent
  2518. buffer.
  2519. Return Value:
  2520. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2521. RPC_P_PACKET_CONSUMED must be returned for all transport
  2522. traffic (success or failure). Anything else will AV the
  2523. runtime.
  2524. --*/
  2525. {
  2526. HTTP2SendContext *HttpSendContext = (HTTP2SendContext *)SendContext;
  2527. WS_HTTP2_CONNECTION *RawConnection;
  2528. RPC_STATUS RpcStatus;
  2529. LOG_FN_OPERATION_ENTRY(HTTP2LOG_COMPLEX_T_SEND, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)HttpSendContext);
  2530. *Buffer = HttpSendContext->pWriteBuffer;
  2531. RawConnection = (WS_HTTP2_CONNECTION *)HttpSendContext->Write.pAsyncObject;
  2532. RpcStatus = RawConnection->ProcessSendComplete(EventStatus, HttpSendContext);
  2533. LOG_FN_OPERATION_EXIT(HTTP2LOG_COMPLEX_T_SEND, HTTP2LOG_OT_CALLBACK, RpcStatus);
  2534. return RpcStatus;
  2535. }
  2536. RPC_STATUS ProxyAsyncCompleteHelper (
  2537. IN HTTP2Channel *TopChannel,
  2538. IN RPC_STATUS CurrentStatus
  2539. )
  2540. /*++
  2541. Routine Description:
  2542. A helper function that completes an async io.
  2543. Arguments:
  2544. TopChannel - the top channel for the stack
  2545. CurrentStatus - the status with which the complete
  2546. notification completed.
  2547. Return Value:
  2548. RPC_S_OK.
  2549. --*/
  2550. {
  2551. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  2552. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  2553. if ((CurrentStatus != RPC_S_OK)
  2554. &&
  2555. (CurrentStatus != RPC_P_PACKET_CONSUMED))
  2556. {
  2557. // if this failed, abort the whole connection
  2558. TopChannel->AbortAndDestroyConnection(CurrentStatus);
  2559. }
  2560. TopChannel->RemoveReference();
  2561. return RPC_S_OK;
  2562. }
  2563. RPCRTAPI
  2564. RPC_STATUS
  2565. RPC_ENTRY
  2566. HTTP2TestHook (
  2567. IN SystemFunction001Commands FunctionCode,
  2568. IN void *InData,
  2569. OUT void *OutData
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. Test hook for the http functions
  2574. Arguments:
  2575. FunctionCode - which test function to perform
  2576. InData - input data from the test function
  2577. OutData - output data from the test function
  2578. Return Value:
  2579. RPC_S_OK or RPC_S_* error
  2580. --*/
  2581. {
  2582. RPC_CHAR *NewTarget;
  2583. switch (FunctionCode)
  2584. {
  2585. case sf001cHttpSetInChannelTarget:
  2586. NewTarget = (RPC_CHAR *)InData;
  2587. if (InChannelTargetTestOverride)
  2588. {
  2589. delete [] InChannelTargetTestOverride;
  2590. InChannelTargetTestOverride = NULL;
  2591. }
  2592. if (NewTarget)
  2593. {
  2594. InChannelTargetTestOverride = DuplicateString(NewTarget);
  2595. if (InChannelTargetTestOverride == NULL)
  2596. return RPC_S_OUT_OF_MEMORY;
  2597. }
  2598. break;
  2599. case sf001cHttpSetOutChannelTarget:
  2600. NewTarget = (RPC_CHAR *)InData;
  2601. if (OutChannelTargetTestOverride)
  2602. {
  2603. delete [] OutChannelTargetTestOverride;
  2604. OutChannelTargetTestOverride = NULL;
  2605. }
  2606. if (NewTarget)
  2607. {
  2608. OutChannelTargetTestOverride = DuplicateString(NewTarget);
  2609. if (OutChannelTargetTestOverride == NULL)
  2610. return RPC_S_OUT_OF_MEMORY;
  2611. }
  2612. break;
  2613. default:
  2614. // we should never be called with a value we can't handle
  2615. ASSERT(0);
  2616. return RPC_S_INTERNAL_ERROR;
  2617. }
  2618. return RPC_S_OK;
  2619. }
  2620. /*********************************************************************
  2621. HTTP2TransportChannel
  2622. *********************************************************************/
  2623. RPC_STATUS HTTP2TransportChannel::Send (
  2624. IN OUT HTTP2SendContext *SendContext
  2625. )
  2626. /*++
  2627. Routine Description:
  2628. Send request
  2629. Arguments:
  2630. SendContext - the send context
  2631. Return Value:
  2632. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2633. --*/
  2634. {
  2635. VerifyValidSendContext(SendContext);
  2636. return LowerLayer->Send(SendContext);
  2637. }
  2638. RPC_STATUS HTTP2TransportChannel::Receive (
  2639. IN HTTP2TrafficType TrafficType
  2640. )
  2641. /*++
  2642. Routine Description:
  2643. Receive request
  2644. Arguments:
  2645. TrafficType - the type of traffic we want to receive
  2646. Return Value:
  2647. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2648. --*/
  2649. {
  2650. return LowerLayer->Receive(TrafficType);
  2651. }
  2652. RPC_STATUS HTTP2TransportChannel::SendComplete (
  2653. IN RPC_STATUS EventStatus,
  2654. IN OUT HTTP2SendContext *SendContext
  2655. )
  2656. /*++
  2657. Routine Description:
  2658. Send complete notification
  2659. Arguments:
  2660. EventStatus - the status of the send
  2661. SendContext - send context
  2662. Return Value:
  2663. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2664. --*/
  2665. {
  2666. return UpperLayer->SendComplete(EventStatus,
  2667. SendContext
  2668. );
  2669. }
  2670. RPC_STATUS HTTP2TransportChannel::ReceiveComplete (
  2671. IN RPC_STATUS EventStatus,
  2672. IN HTTP2TrafficType TrafficType,
  2673. IN BYTE *Buffer,
  2674. IN UINT BufferLength
  2675. )
  2676. /*++
  2677. Routine Description:
  2678. Receive complete notification.
  2679. Arguments:
  2680. EventStatus - status of the operation
  2681. TrafficType - the type of traffic we have received
  2682. Buffer - the received buffer (success only)
  2683. BufferLength - the length of the received buffer (success only)
  2684. Return Value:
  2685. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  2686. --*/
  2687. {
  2688. return UpperLayer->ReceiveComplete(EventStatus,
  2689. TrafficType,
  2690. Buffer,
  2691. BufferLength
  2692. );
  2693. }
  2694. void HTTP2TransportChannel::Abort (
  2695. IN RPC_STATUS RpcStatus
  2696. )
  2697. /*++
  2698. Routine Description:
  2699. Abort the channel
  2700. Arguments:
  2701. RpcStatus - the error code with which we abort
  2702. Return Value:
  2703. --*/
  2704. {
  2705. LowerLayer->Abort(RpcStatus);
  2706. }
  2707. void HTTP2TransportChannel::SendCancelled (
  2708. IN HTTP2SendContext *SendContext
  2709. )
  2710. /*++
  2711. Routine Description:
  2712. A lower channel cancelled a send already passed through this channel.
  2713. Most channels don't care as they don't account for or hang on to sends.
  2714. Called only in submission context.
  2715. Arguments:
  2716. SendContext - the send context of the send that was cancelled
  2717. Return Value:
  2718. --*/
  2719. {
  2720. UpperLayer->SendCancelled(SendContext);
  2721. }
  2722. void HTTP2TransportChannel::Reset (
  2723. void
  2724. )
  2725. /*++
  2726. Routine Description:
  2727. Reset the channel for next open/send/receive. This is
  2728. used in submission context only and implies there are no
  2729. pending operations on the channel. It is used on the client
  2730. during opening the connection to do quick negotiation on the
  2731. same connection instead of opening a new connection every time.
  2732. Arguments:
  2733. Return Value:
  2734. --*/
  2735. {
  2736. if (LowerLayer)
  2737. LowerLayer->Reset();
  2738. }
  2739. RPC_STATUS HTTP2TransportChannel::AsyncCompleteHelper (
  2740. IN RPC_STATUS CurrentStatus
  2741. )
  2742. /*++
  2743. Routine Description:
  2744. Helper routine that helps complete an async operation
  2745. Arguments:
  2746. CurrentStatus - the current status of the operation
  2747. Return Value:
  2748. The status to return to the runtime.
  2749. --*/
  2750. {
  2751. return TopChannel->AsyncCompleteHelper(CurrentStatus);
  2752. }
  2753. RPC_STATUS HTTP2TransportChannel::HandleSendResultFromNeutralContext (
  2754. IN RPC_STATUS CurrentStatus
  2755. )
  2756. /*++
  2757. Routine Description:
  2758. Handles the result code from send from a neutral context.
  2759. This includes checking for channel recycling and intiating
  2760. one if necessary. This routine simply delegates to the top channel
  2761. Arguments:
  2762. CurrentStatus - the status from the send operation
  2763. Return Value:
  2764. RPC_S_OK or RPC_S_*. Callers may ignore it since all cleanup was
  2765. done.
  2766. Notes:
  2767. This must be called in upcall or neutral context only
  2768. --*/
  2769. {
  2770. return TopChannel->HandleSendResultFromNeutralContext(CurrentStatus);
  2771. }
  2772. /*********************************************************************
  2773. WS_HTTP2_CONNECTION
  2774. *********************************************************************/
  2775. RPC_STATUS WS_HTTP2_CONNECTION::Send(HANDLE hFile, LPCVOID lpBuffer,
  2776. DWORD nNumberOfBytesToWrite,
  2777. LPDWORD lpNumberOfBytesWritten,
  2778. LPOVERLAPPED lpOverlapped)
  2779. /*++
  2780. Routine Description:
  2781. Does an asynchronous send on the connection.
  2782. Arguments:
  2783. hFile - file to send on
  2784. lpBuffer - buffer to send
  2785. nNumberOfBytesToWrite - number of bytes to send
  2786. lpNumberOfBytesWritten - number of bytes written. Will never get filled
  2787. in this code path because it is async.
  2788. lpOverlapped - overlapped to use for the operation
  2789. Return Value:
  2790. WSA Error Code
  2791. --*/
  2792. {
  2793. // See Rule 32.
  2794. return UTIL_WriteFile2(hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped);
  2795. }
  2796. RPC_STATUS WS_HTTP2_CONNECTION::Receive(HANDLE hFile,
  2797. LPVOID lpBuffer,
  2798. DWORD nNumberOfBytesToRead,
  2799. LPDWORD lpNumberOfBytesRead,
  2800. LPOVERLAPPED lpOverlapped
  2801. )
  2802. /*++
  2803. Routine Description:
  2804. Does an asynchronous receive on the connection.
  2805. Arguments:
  2806. hFile - file to receive on
  2807. lpBuffer - buffer to receive into
  2808. nNumberOfBytesToRead - number of bytes to receive
  2809. lpNumberOfBytesRead - number of bytes read. Will never get filled
  2810. in this code path because it is async.
  2811. lpOverlapped - overlapped to use for the operation
  2812. Return Value:
  2813. WSA Error Code
  2814. --*/
  2815. {
  2816. return SANReceive(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
  2817. }
  2818. RPC_STATUS WS_HTTP2_CONNECTION::ProcessReceiveFailed (
  2819. IN RPC_STATUS EventStatus
  2820. )
  2821. /*++
  2822. Routine Description:
  2823. Notifies a raw connection of receive failure.
  2824. Arguments:
  2825. EventStatus - error with which the receive failed
  2826. Return Value:
  2827. RPC_S_OK to return packet to runtime
  2828. or RPC_P_PACKET_CONSUMED to hide it.
  2829. --*/
  2830. {
  2831. // if we failed before we parsed the header, chances are the problem
  2832. // was with the header format. Treat it as protocol error.
  2833. if ((HeaderRead == FALSE) && (EventStatus == RPC_P_CONNECTION_SHUTDOWN))
  2834. EventStatus = RPC_S_PROTOCOL_ERROR;
  2835. return Channel->ReceiveComplete(EventStatus, http2ttRaw, pReadBuffer, 0);
  2836. }
  2837. RPC_STATUS WS_HTTP2_CONNECTION::ProcessSendComplete (
  2838. IN RPC_STATUS EventStatus,
  2839. IN CO_SEND_CONTEXT *SendContext
  2840. )
  2841. /*++
  2842. Routine Description:
  2843. Notifies a raw connection of send completion (fail or succeed).
  2844. Arguments:
  2845. EventStatus - error with which the send failed
  2846. Return Value:
  2847. RPC_S_OK to return packet to runtime
  2848. or RPC_P_PACKET_CONSUMED to hide it.
  2849. --*/
  2850. {
  2851. HTTP2SendContext *HttpSendContext = (HTTP2SendContext *)SendContext;
  2852. VerifyValidSendContext(HttpSendContext);
  2853. return Channel->SendComplete(EventStatus, HttpSendContext);
  2854. }
  2855. RPC_STATUS WS_HTTP2_CONNECTION::ProcessRead(
  2856. IN DWORD bytes,
  2857. OUT BUFFER *pBuffer,
  2858. OUT PUINT pBufferLength
  2859. )
  2860. /*++
  2861. Routine Description:
  2862. Processes a connection oriented receive
  2863. complete. But in HTTP2 we no-op this and do all read
  2864. processing through the COMPLEX_T mechanism.
  2865. Arguments:
  2866. bytes - the number of read (not including those in iLastRead).
  2867. pBuffer - when returning RPC_S_OK will contain the message.
  2868. pBufferLength - when return RPC_S_OK will contain the message length.
  2869. Return Value:
  2870. RPC_S_OK
  2871. --*/
  2872. {
  2873. return RPC_S_OK;
  2874. }
  2875. RPC_STATUS WS_HTTP2_CONNECTION::ProcessReceiveComplete(
  2876. IN DWORD bytes,
  2877. OUT BUFFER *pBuffer,
  2878. OUT PUINT pBufferLength
  2879. )
  2880. /*++
  2881. Routine Description:
  2882. Processes a connection oriented receive
  2883. complete. It takes care of fragmentation.
  2884. Arguments:
  2885. bytes - the number of read (not including those in iLastRead).
  2886. pBuffer - when returning RPC_S_OK will contain the message.
  2887. pBufferLength - when return RPC_S_OK will contain the message length.
  2888. Return Value:
  2889. RPC_S_OK to return packet to runtime
  2890. or RPC_P_PACKET_CONSUMED to hide it.
  2891. --*/
  2892. {
  2893. RPC_STATUS RpcStatus;
  2894. if (HeaderRead)
  2895. {
  2896. RpcStatus = BASE_CONNECTION::ProcessRead(bytes, pBuffer, pBufferLength);
  2897. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2898. return RpcStatus;
  2899. }
  2900. else if (bytes != 0)
  2901. {
  2902. ASSERT(ReadHeaderFn);
  2903. RpcStatus = ReadHeaderFn(this,
  2904. bytes,
  2905. (ULONG *)pBufferLength
  2906. );
  2907. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2908. return RpcStatus;
  2909. if (RpcStatus == RPC_S_OK)
  2910. {
  2911. RpcStatus = BASE_CONNECTION::ProcessRead(*pBufferLength, pBuffer, pBufferLength);
  2912. }
  2913. if (RpcStatus == RPC_P_PARTIAL_RECEIVE)
  2914. return RpcStatus;
  2915. }
  2916. else
  2917. {
  2918. RpcStatus = RPC_P_CONNECTION_CLOSED;
  2919. }
  2920. // we corrupt the RTS packet if necessary
  2921. if ( gfRPCVerifierEnabled && (pRpcVerifierSettings->fCorruptionInjectServerReceives) && (RpcStatus == RPC_S_OK) )
  2922. {
  2923. if (IsRTSPacket(*pBuffer))
  2924. {
  2925. CorruptionInject(ServerReceive,
  2926. (UINT *)pBufferLength,
  2927. (void **)pBuffer);
  2928. LogEvent(SU_CORRUPT, EV_NOTIFY, *pBuffer, this, *pBufferLength, 0, 0);
  2929. }
  2930. }
  2931. if (RpcStatus == RPC_S_OK)
  2932. {
  2933. RpcStatus = Channel->ReceiveComplete(RpcStatus,
  2934. http2ttRaw,
  2935. (BYTE *)*pBuffer,
  2936. *pBufferLength);
  2937. }
  2938. else
  2939. {
  2940. RpcStatus = Channel->ReceiveComplete(RpcStatus,
  2941. http2ttRaw,
  2942. NULL,
  2943. 0);
  2944. }
  2945. return RpcStatus;
  2946. }
  2947. RPC_STATUS WS_HTTP2_CONNECTION::Abort (
  2948. void
  2949. )
  2950. /*++
  2951. Routine Description:
  2952. No-op. This is called from common
  2953. transport code. We don't abort HTTP2
  2954. connections from common transport code. Ignore
  2955. this call.
  2956. Arguments:
  2957. Return Value:
  2958. RPC_S_OK
  2959. --*/
  2960. {
  2961. return RPC_S_OK;
  2962. }
  2963. void WS_HTTP2_CONNECTION::Free (
  2964. void
  2965. )
  2966. /*++
  2967. Routine Description:
  2968. Acts like destructor. All memory needs to
  2969. be freed.
  2970. Arguments:
  2971. Return Value:
  2972. RPC_S_OK
  2973. --*/
  2974. {
  2975. if (pReadBuffer)
  2976. {
  2977. RpcFreeBuffer(pReadBuffer);
  2978. pReadBuffer = NULL;
  2979. }
  2980. // This may be called on a partially initialized connection
  2981. // during its migration. Ignore such calls.
  2982. if (fIgnoreFree)
  2983. return;
  2984. // Unlink the object from the PnP list.
  2985. TransportProtocol::RemoveObjectFromProtocolList(this);
  2986. // Make sure we don't free the connection without closing the socket.
  2987. // When we close the socket, we set it to NULL.
  2988. ASSERT(Conn.Socket == NULL);
  2989. }
  2990. void WS_HTTP2_CONNECTION::RealAbort (
  2991. void
  2992. )
  2993. /*++
  2994. Routine Description:
  2995. Aborts an HTTP2 connection.
  2996. Arguments:
  2997. Return Value:
  2998. --*/
  2999. {
  3000. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_RAW_CONNECTION, 0);
  3001. (void)WS_CONNECTION::Abort();
  3002. }
  3003. void WS_HTTP2_CONNECTION::Initialize (
  3004. void
  3005. )
  3006. /*++
  3007. Routine Description:
  3008. Initializes a raw connection
  3009. Arguments:
  3010. Return Value:
  3011. --*/
  3012. {
  3013. BASE_CONNECTION::Initialize();
  3014. #if DBG
  3015. // client and server virtual connections must initialize this. In debug
  3016. // builds toast anybody who forgets. Proxies don't care
  3017. type = 0xC0C0C0C0;
  3018. #endif
  3019. pAddress = NULL;
  3020. RpcpInitializeListHead(&ObjectList);
  3021. fIgnoreFree = FALSE;
  3022. // use explicit placement to initialize the vtable. We need this to
  3023. // be able to use the virtual functions
  3024. (void) new (this) WS_HTTP2_CONNECTION;
  3025. }
  3026. /*********************************************************************
  3027. WS_HTTP2_INITIAL_CONNECTION
  3028. *********************************************************************/
  3029. C_ASSERT(sizeof(rpcconn_common) == sizeof(CONN_RPC_HEADER));
  3030. RPC_STATUS WS_HTTP2_INITIAL_CONNECTION::ProcessRead(
  3031. IN DWORD BytesRead,
  3032. OUT BUFFER *pBuffer,
  3033. OUT PUINT pBufferLength
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. Processes a connection oriented receive
  3038. complete. It determines whether HTTP2 or HTTP will be
  3039. used. For HTTP2, the actual work is done in
  3040. HTTP2ProcessComplexTReceive.
  3041. Arguments:
  3042. BytesRead - the number of read (not including those in iLastRead).
  3043. pBuffer - when returning RPC_S_OK will contain the message.
  3044. pBufferLength - when return RPC_S_OK will contain the message length.
  3045. Return Value:
  3046. RPC_S_OK for successful processing
  3047. RPC_PARTIAL_RECEIVE - not enough was received to tell
  3048. RPC_P_RECEIVE_FAILED - error occurred.
  3049. RPC_P_INITIALIZE_HTTP2_CONNECTION - offload the connection establishment to HTTP2ProcessComplexTReceive.
  3050. --*/
  3051. {
  3052. RPC_STATUS RpcStatus;
  3053. BYTE *Packet;
  3054. RpcStatus = BASE_CONNECTION::ProcessRead(BytesRead,
  3055. pBuffer,
  3056. pBufferLength
  3057. );
  3058. if (RpcStatus == RPC_S_OK)
  3059. {
  3060. // ProcessRead guarantees that on return value of RPC_S_OK
  3061. // we have at least rpcconn_common bytes read successfully
  3062. Packet = (BYTE *)*pBuffer;
  3063. if (IsRTSPacket(Packet))
  3064. {
  3065. // The final initialization will take place in HTTP2ProcessComplexTReceive.
  3066. this->type |= COMPLEX_T;
  3067. // Signal to HTTP2ProcessComplexTReceive that we are in the process of
  3068. // connection establishment by returning RPC_P_INITIALIZE_HTTP2_CONNECTION.
  3069. RpcStatus = RPC_P_INITIALIZE_HTTP2_CONNECTION;
  3070. }
  3071. else
  3072. {
  3073. // morph the connection into WS_CONNECTION to serve
  3074. // HTTP requests. The only thing we need to change is the
  3075. // vtable. We have a little bit of extra goo at the end, but
  3076. // that's ok.
  3077. (void) new (this) WS_CONNECTION;
  3078. }
  3079. }
  3080. return RpcStatus;
  3081. }
  3082. RPC_STATUS WS_HTTP2_INITIAL_CONNECTION::Abort(
  3083. void
  3084. )
  3085. /*++
  3086. Routine Description:
  3087. Aborts an WS_HTTP2_INITIAL_CONNECTION connection.
  3088. Very rare to be called.
  3089. Arguments:
  3090. Return Value:
  3091. RPC_S_OK
  3092. --*/
  3093. {
  3094. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_INITIAL_RAW_CONNECTION, 0);
  3095. WS_HTTP2_CONNECTION::RealAbort();
  3096. return RPC_S_OK;
  3097. }
  3098. /*********************************************************************
  3099. HTTP2BottomChannel
  3100. *********************************************************************/
  3101. RPC_STATUS HTTP2BottomChannel::SendComplete (
  3102. IN RPC_STATUS EventStatus,
  3103. IN OUT HTTP2SendContext *SendContext
  3104. )
  3105. /*++
  3106. Routine Description:
  3107. Send complete notification
  3108. Arguments:
  3109. EventStatus - status of the operation
  3110. SendContext - the send context
  3111. Return Value:
  3112. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3113. --*/
  3114. {
  3115. RPC_STATUS RpcStatus;
  3116. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, EventStatus);
  3117. RpcStatus = HTTP2TransportChannel::SendComplete(EventStatus,
  3118. SendContext
  3119. );
  3120. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, RpcStatus);
  3121. return AsyncCompleteHelper(RpcStatus);
  3122. }
  3123. RPC_STATUS HTTP2BottomChannel::ReceiveComplete (
  3124. IN RPC_STATUS EventStatus,
  3125. IN HTTP2TrafficType TrafficType,
  3126. IN BYTE *Buffer,
  3127. IN UINT BufferLength
  3128. )
  3129. /*++
  3130. Routine Description:
  3131. Receive complete notification
  3132. Arguments:
  3133. EventStatus - status of the operation
  3134. TrafficType - the type of traffic we have received
  3135. Buffer - the received buffer (success only)
  3136. BufferLength - the length of the received buffer (success only)
  3137. Return Value:
  3138. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3139. --*/
  3140. {
  3141. RPC_STATUS RpcStatus;
  3142. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, EventStatus);
  3143. RpcStatus = HTTP2TransportChannel::ReceiveComplete(EventStatus,
  3144. TrafficType,
  3145. Buffer,
  3146. BufferLength
  3147. );
  3148. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_BOTTOM_CHANNEL, RpcStatus);
  3149. return AsyncCompleteHelper(RpcStatus);
  3150. }
  3151. /*********************************************************************
  3152. HTTP2SocketTransportChannel
  3153. *********************************************************************/
  3154. RPC_STATUS HTTP2SocketTransportChannel::Send (
  3155. IN OUT HTTP2SendContext *SendContext
  3156. )
  3157. /*++
  3158. Routine Description:
  3159. Send request. Forward the send to the raw connection
  3160. Arguments:
  3161. SendContext - the send context
  3162. Return Value:
  3163. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3164. --*/
  3165. {
  3166. RPC_STATUS RpcStatus;
  3167. DWORD Ignored;
  3168. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, (ULONG_PTR)SendContext);
  3169. // route this through the completion port
  3170. SendContext->Write.ol.hEvent = NULL;
  3171. SendContext->Write.pAsyncObject = RawConnection;
  3172. // N.B. The Winsock provider will touch the overlapped on the return path. We need
  3173. // to make sure that either the overlapped is around (in which case we can use WSASend),
  3174. // or otherwise use UTIL_WriteFile2 which does not touch the overlapped on return.
  3175. // We know the overlapped may not be around when this is a proxy data send, any type
  3176. // of RTS send, or abandoned send. All non-proxy, not-abandoned data sends will have
  3177. // the overlapped around.
  3178. if ((SendContext->TrafficType == http2ttData)
  3179. && (((SendContext->Flags & (SendContextFlagAbandonedSend | SendContextFlagProxySend)) == 0)))
  3180. {
  3181. RpcStatus = RawConnection->WS_HTTP2_CONNECTION::SANSend(
  3182. RawConnection->Conn.Handle,
  3183. SendContext->pWriteBuffer,
  3184. SendContext->maxWriteBuffer,
  3185. &Ignored,
  3186. &SendContext->Write.ol
  3187. );
  3188. }
  3189. else
  3190. {
  3191. RpcStatus = RawConnection->WS_HTTP2_CONNECTION::Send(
  3192. RawConnection->Conn.Handle,
  3193. SendContext->pWriteBuffer,
  3194. SendContext->maxWriteBuffer,
  3195. &Ignored,
  3196. &SendContext->Write.ol
  3197. );
  3198. }
  3199. if ( (RpcStatus != RPC_S_OK)
  3200. && (RpcStatus != ERROR_IO_PENDING) )
  3201. {
  3202. VALIDATE(RpcStatus)
  3203. {
  3204. ERROR_NETNAME_DELETED,
  3205. ERROR_GRACEFUL_DISCONNECT,
  3206. ERROR_NO_DATA,
  3207. ERROR_NO_SYSTEM_RESOURCES,
  3208. ERROR_WORKING_SET_QUOTA,
  3209. ERROR_BAD_COMMAND,
  3210. ERROR_OPERATION_ABORTED,
  3211. ERROR_WORKING_SET_QUOTA,
  3212. WSAECONNABORTED,
  3213. WSAECONNRESET
  3214. } END_VALIDATE;
  3215. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, RPC_P_SEND_FAILED);
  3216. return(RPC_P_SEND_FAILED);
  3217. }
  3218. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SOCKET_CHANNEL, RPC_S_OK);
  3219. return RPC_S_OK;
  3220. }
  3221. RPC_STATUS HTTP2SocketTransportChannel::Receive (
  3222. IN HTTP2TrafficType TrafficType
  3223. )
  3224. {
  3225. RPC_STATUS RpcStatus;
  3226. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_SOCKET_CHANNEL, TrafficType);
  3227. ASSERT(TrafficType == http2ttRaw);
  3228. RpcStatus = CO_Recv(RawConnection);
  3229. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_SOCKET_CHANNEL, RpcStatus);
  3230. return RpcStatus;
  3231. }
  3232. void HTTP2SocketTransportChannel::Abort (
  3233. IN RPC_STATUS RpcStatus
  3234. )
  3235. /*++
  3236. Routine Description:
  3237. Abort the channel
  3238. Arguments:
  3239. RpcStatus - the error code with which we abort
  3240. Return Value:
  3241. --*/
  3242. {
  3243. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_SOCKET_CHANNEL, RpcStatus);
  3244. RawConnection->RealAbort();
  3245. }
  3246. void HTTP2SocketTransportChannel::FreeObject (
  3247. void
  3248. )
  3249. /*++
  3250. Routine Description:
  3251. Frees the object. Acts like a destructor for the
  3252. channel.
  3253. Arguments:
  3254. Return Value:
  3255. --*/
  3256. {
  3257. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_SOCKET_CHANNEL, 0);
  3258. RawConnection->Free();
  3259. HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  3260. }
  3261. void HTTP2SocketTransportChannel::Reset (
  3262. void
  3263. )
  3264. /*++
  3265. Routine Description:
  3266. Reset the channel for next open/send/receive. This is
  3267. used in submission context only and implies there are no
  3268. pending operations on the channel. It is used on the client
  3269. during opening the connection to do quick negotiation on the
  3270. same connection instead of opening a new connection every time.
  3271. Arguments:
  3272. Return Value:
  3273. --*/
  3274. {
  3275. RawConnection->HeaderRead = FALSE;
  3276. }
  3277. /*********************************************************************
  3278. HTTP2FragmentReceiver
  3279. *********************************************************************/
  3280. RPC_STATUS HTTP2FragmentReceiver::Receive (
  3281. IN HTTP2TrafficType TrafficType
  3282. )
  3283. /*++
  3284. Routine Description:
  3285. Receive request
  3286. Arguments:
  3287. TrafficType - the type of traffic we want to receive
  3288. Return Value:
  3289. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  3290. --*/
  3291. {
  3292. if (iLastRead && iLastRead == MaxReadBuffer)
  3293. {
  3294. ASSERT(pReadBuffer);
  3295. // This means we received a coalesced read of a complete
  3296. // message. (Or that we received a coalesced read < header size)
  3297. // We should complete that as it's own IO in neutral context.
  3298. // This is very rare.
  3299. (void) COMMON_PostRuntimeEvent(GetPostRuntimeEvent(),
  3300. this
  3301. );
  3302. return(RPC_S_OK);
  3303. }
  3304. ASSERT(iLastRead == 0 || (iLastRead < MaxReadBuffer));
  3305. return(PostReceive());
  3306. };
  3307. RPC_STATUS HTTP2FragmentReceiver::ReceiveComplete (
  3308. IN RPC_STATUS EventStatus,
  3309. IN HTTP2TrafficType TrafficType,
  3310. IN OUT BYTE **Buffer,
  3311. IN OUT UINT *BufferLength
  3312. )
  3313. /*++
  3314. Routine Description:
  3315. Processes a receive complete notification.
  3316. Arguments:
  3317. EventStatus - the status code of the operation.
  3318. TrafficType - the type of traffic we have received
  3319. Buffer - the buffer. Must be NULL at this level on input. On
  3320. output contains the buffer for the current receive. If NULL
  3321. on output, we did not have a full packet. Undefined on failure.
  3322. BufferLength - the actual number of bytes received. On output the
  3323. number of bytes for the current packet. If 0 on output,
  3324. we did not have a complete packet. Undefined on failure.
  3325. Return Value:
  3326. RPC_S_OK or RPC_S_* error. Note that unlike BASE_CONNECTION::ProcessRead,
  3327. this function does not return RPC_P_PARTIAL_RECEIVE. See note section for
  3328. more information.
  3329. Note:
  3330. NULL returned Buffer and RPC_S_OK means a partial receive.
  3331. --*/
  3332. {
  3333. BYTE *LocalReadBuffer;
  3334. ULONG MessageSize;
  3335. ULONG ExtraSize;
  3336. ULONG AllocSize;
  3337. BYTE *NewBuffer;
  3338. BOOL DoNotComplete;
  3339. ULONG LocalBufferLength = *BufferLength;
  3340. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_FRAGMENT_RECEIVER, LocalBufferLength);
  3341. DoNotComplete = FALSE;
  3342. if (EventStatus == RPC_S_OK)
  3343. {
  3344. ASSERT(pReadBuffer);
  3345. LocalBufferLength += iLastRead;
  3346. ASSERT(LocalBufferLength <= MaxReadBuffer);
  3347. if (LocalBufferLength < sizeof(CONN_RPC_HEADER))
  3348. {
  3349. // Not a whole header, resubmit the read and continue.
  3350. iLastRead = LocalBufferLength;
  3351. EventStatus = PostReceive();
  3352. if (EventStatus == RPC_S_OK)
  3353. DoNotComplete = TRUE;
  3354. else
  3355. LocalReadBuffer = NULL;
  3356. }
  3357. else
  3358. {
  3359. MessageSize = MessageLength((PCONN_RPC_HEADER)pReadBuffer);
  3360. if (MessageSize < sizeof(CONN_RPC_HEADER))
  3361. {
  3362. ASSERT(MessageSize >= sizeof(CONN_RPC_HEADER));
  3363. EventStatus = RPC_P_RECEIVE_FAILED;
  3364. LocalReadBuffer = NULL;
  3365. }
  3366. else if (LocalBufferLength == MessageSize)
  3367. {
  3368. // All set, have a complete request.
  3369. LocalReadBuffer = pReadBuffer;
  3370. LocalBufferLength = MessageSize;
  3371. iLastRead = 0;
  3372. pReadBuffer = 0;
  3373. }
  3374. else if (MessageSize > LocalBufferLength)
  3375. {
  3376. // Don't have a complete message, realloc if needed and
  3377. // resubmit a read for the remaining bytes.
  3378. if (MaxReadBuffer < MessageSize)
  3379. {
  3380. // Buffer too small for the message.
  3381. EventStatus = TransConnectionReallocPacket(NULL,
  3382. &pReadBuffer,
  3383. LocalBufferLength,
  3384. MessageSize);
  3385. if (EventStatus == RPC_S_OK)
  3386. {
  3387. // increase the post size, but not if we are in direct
  3388. // buffer mode.
  3389. if (gBCacheMode == BCacheModeCached)
  3390. iPostSize = MessageSize;
  3391. }
  3392. }
  3393. if (EventStatus == RPC_S_OK)
  3394. {
  3395. // Setup to receive exactly the remaining bytes of the message.
  3396. iLastRead = LocalBufferLength;
  3397. MaxReadBuffer = MessageSize;
  3398. EventStatus = PostReceive();
  3399. if (EventStatus == RPC_S_OK)
  3400. DoNotComplete = TRUE;
  3401. else
  3402. LocalReadBuffer = NULL;
  3403. }
  3404. else
  3405. {
  3406. LocalReadBuffer = NULL;
  3407. }
  3408. }
  3409. else
  3410. {
  3411. // Coalesced read, save extra data. Very uncommon
  3412. ASSERT(LocalBufferLength > MessageSize);
  3413. // The first message and size will be returned
  3414. LocalReadBuffer = pReadBuffer;
  3415. ExtraSize = LocalBufferLength - MessageSize;
  3416. LocalBufferLength = MessageSize;
  3417. // Try to find a good size of the extra PDU(s)
  3418. if (ExtraSize < sizeof(CONN_RPC_HEADER))
  3419. {
  3420. // Not a whole header, we'll assume gPostSize;
  3421. AllocSize = gPostSize;
  3422. }
  3423. else
  3424. {
  3425. #ifdef _M_IA64
  3426. // The first packet may not contain a number of bytes
  3427. // that align the second on an 8-byte boundary. Hence, the
  3428. // structure may end up unaligned.
  3429. AllocSize = MessageLengthUnaligned((PCONN_RPC_HEADER)(pReadBuffer
  3430. + MessageSize));
  3431. #else
  3432. AllocSize = MessageLength((PCONN_RPC_HEADER)(pReadBuffer
  3433. + MessageSize));
  3434. #endif
  3435. }
  3436. if (AllocSize < ExtraSize)
  3437. {
  3438. // This can happen if there are more than two PDUs coalesced together
  3439. // in the buffer. Or if the PDU is invalid. Or if the iPostSize is
  3440. // smaller than the next PDU.
  3441. AllocSize = ExtraSize;
  3442. }
  3443. // Allocate a new buffer to save the extra data for the next read.
  3444. NewBuffer = (BYTE *)RpcAllocateBuffer(AllocSize);
  3445. if (0 == NewBuffer)
  3446. {
  3447. // We have a complete request. We could process the request and
  3448. // close the connection only after trying to send the reply.
  3449. LocalReadBuffer = NULL;
  3450. LocalBufferLength = 0;
  3451. EventStatus = RPC_S_OUT_OF_MEMORY;
  3452. }
  3453. else
  3454. {
  3455. ASSERT(pReadBuffer);
  3456. // Save away extra data for the next receive
  3457. RpcpMemoryCopy(NewBuffer,
  3458. pReadBuffer + LocalBufferLength,
  3459. ExtraSize);
  3460. pReadBuffer = NewBuffer;
  3461. iLastRead = ExtraSize;
  3462. MaxReadBuffer = AllocSize;
  3463. ASSERT(iLastRead <= MaxReadBuffer);
  3464. EventStatus = RPC_S_OK;
  3465. }
  3466. }
  3467. }
  3468. }
  3469. else
  3470. {
  3471. // in failure cases we keep the buffer. We will
  3472. // free it on Abort.
  3473. LocalReadBuffer = NULL;
  3474. }
  3475. if (DoNotComplete == FALSE)
  3476. {
  3477. *Buffer = LocalReadBuffer;
  3478. *BufferLength = LocalBufferLength;
  3479. if (gfRPCVerifierEnabled)
  3480. {
  3481. // check whether we are on the proxy side or client side.
  3482. // Currently only those two use the HTTP2FragmentReceiver
  3483. if (TopChannel->IsProxyChannel())
  3484. {
  3485. CorruptionInject(ServerReceive,
  3486. (UINT *)&LocalBufferLength,
  3487. (void **)&LocalReadBuffer);
  3488. }
  3489. else
  3490. {
  3491. CorruptionInject(ClientReceive,
  3492. (UINT *)&LocalBufferLength,
  3493. (void **)&LocalReadBuffer);
  3494. }
  3495. }
  3496. EventStatus = UpperLayer->ReceiveComplete(EventStatus,
  3497. TrafficType,
  3498. LocalReadBuffer,
  3499. LocalBufferLength
  3500. );
  3501. EventStatus = AsyncCompleteHelper(EventStatus);
  3502. // don't touch the this pointer after AsyncCompleteHelper.
  3503. // It could be gone.
  3504. }
  3505. else
  3506. {
  3507. *Buffer = NULL;
  3508. *BufferLength = 0;
  3509. EventStatus = RPC_S_OK;
  3510. }
  3511. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_FRAGMENT_RECEIVER, *BufferLength);
  3512. return EventStatus;
  3513. }
  3514. RPC_STATUS HTTP2FragmentReceiver::DepositReceivedData (
  3515. IN ULONG DataSize,
  3516. IN BYTE *Data
  3517. )
  3518. /*++
  3519. Routine Description:
  3520. Deposits data directly in the receive queue. That is, the
  3521. data arriving from this method will be posted in such a way as
  3522. if they were received from the network on a previous receive.
  3523. This means receive complete will not be issued for this call
  3524. and another receive must be issued to retrieve the data passed
  3525. in.
  3526. Arguments:
  3527. DataSize - the size of the data buffer.
  3528. Data - the buffer itself. This function makes its own copy of the
  3529. data. Caller is responsible for freeing the passed in
  3530. parameter.
  3531. Return Value:
  3532. Notes:
  3533. Currently the method is structured to function correctly only
  3534. when no data already received exist. It will ASSERT if data
  3535. are already present. It is straightforward to rework the method
  3536. to append the incoming data to existing data, but it's not
  3537. necessary as it will be currently called on first data chunk
  3538. only.
  3539. --*/
  3540. {
  3541. // make sure that this happens only when there are no
  3542. // accumulated data
  3543. ASSERT (iLastRead == 0);
  3544. if (pReadBuffer == NULL)
  3545. {
  3546. pReadBuffer = (BYTE *)RpcAllocateBuffer(DataSize);
  3547. if (pReadBuffer == NULL)
  3548. return RPC_S_OUT_OF_MEMORY;
  3549. }
  3550. RpcpMemoryCopy (pReadBuffer, Data, DataSize);
  3551. iLastRead = DataSize;
  3552. MaxReadBuffer = DataSize;
  3553. return RPC_S_OK;
  3554. }
  3555. /*********************************************************************
  3556. HTTP2WinHttpTransportChannel
  3557. *********************************************************************/
  3558. // our public constants are aligned with HTTP constants. Even though it is
  3559. // unlikely for either to change, make sure they don't. If they do, we need
  3560. // a remapping function as we use them interchangeably in the code
  3561. C_ASSERT(WINHTTP_AUTH_SCHEME_BASIC == RPC_C_HTTP_AUTHN_SCHEME_BASIC);
  3562. C_ASSERT(WINHTTP_AUTH_SCHEME_NTLM == RPC_C_HTTP_AUTHN_SCHEME_NTLM);
  3563. C_ASSERT(WINHTTP_AUTH_SCHEME_PASSPORT == RPC_C_HTTP_AUTHN_SCHEME_PASSPORT);
  3564. C_ASSERT(WINHTTP_AUTH_SCHEME_DIGEST == RPC_C_HTTP_AUTHN_SCHEME_DIGEST);
  3565. C_ASSERT(WINHTTP_AUTH_SCHEME_NEGOTIATE == RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE);
  3566. HTTP2WinHttpTransportChannel::HTTP2WinHttpTransportChannel (
  3567. OUT RPC_STATUS *RpcStatus
  3568. ) : Mutex (RpcStatus)
  3569. /*++
  3570. Routine Description:
  3571. HTTP2WinHttpTransportChannel constructor.
  3572. Arguments:
  3573. RpcStatus - on output will contain the result of the
  3574. initialization.
  3575. Return Value:
  3576. --*/
  3577. {
  3578. hSession = NULL;
  3579. hConnect = NULL;
  3580. hRequest = NULL;
  3581. SyncEvent = NULL;
  3582. RpcpInitializeListHead(&BufferQueueHead);
  3583. SendsPending = 0;
  3584. State = whtcsNew;
  3585. AsyncError = RPC_S_INTERNAL_ERROR;
  3586. HttpCredentials = NULL;
  3587. KeepAlive = FALSE;
  3588. CredentialsSetForScheme = 0;
  3589. PreviousRequestContentLength = -1;
  3590. ChosenAuthScheme = 0;
  3591. DelayedReceiveTrafficType = http2ttNone;
  3592. CurrentSendContext = NULL;
  3593. }
  3594. const RPC_CHAR ContentLengthHeader[] = L"Content-Length:";
  3595. RPC_STATUS HTTP2WinHttpTransportChannel::Open (
  3596. IN HTTPResolverHint *Hint,
  3597. IN const RPC_CHAR *Verb,
  3598. IN const RPC_CHAR *Url,
  3599. IN const RPC_CHAR *AcceptType,
  3600. IN ULONG ContentLength,
  3601. IN ULONG CallTimeout,
  3602. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  3603. IN ULONG ChosenAuthScheme,
  3604. IN const BYTE *AdditionalData OPTIONAL
  3605. )
  3606. /*++
  3607. Routine Description:
  3608. Opens the connection to the proxy. We know that a failed Open
  3609. will be followed by Abort.
  3610. Arguments:
  3611. Hint - the resolver hint
  3612. Verb - the verb to use.
  3613. Url - the url to connect to.
  3614. AcceptType - string representation of the accept type.
  3615. ContentLength - the content length for the request (i.e. the
  3616. channel lifetime)
  3617. CallTimeout - the timeout for the operation
  3618. HttpCredentials - the HTTP transport credentials
  3619. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  3620. AdditionalData - additional data to send with the header. Must be set iff
  3621. AdditionalDataLength != 0
  3622. Return Value:
  3623. RPC_S_OK or RPC_S_* error.
  3624. --*/
  3625. {
  3626. BOOL HttpResult = FALSE;
  3627. DWORD dwReadBufferSizeSize = sizeof(ULONG);
  3628. ULONG WinHttpAccessType;
  3629. LPCWSTR AcceptTypes[2];
  3630. ULONG LastError;
  3631. RPC_CHAR *UnicodeString;
  3632. ULONG UnicodeStringSize; // in characters including null terminated NULL
  3633. RPC_STATUS RpcStatus;
  3634. ULONG FlagsToAdd;
  3635. RPC_HTTP_TRANSPORT_CREDENTIALS_W *TransHttpCredentials;
  3636. ULONG AdditionalDataLengthToUse;
  3637. ULONG ContentLengthToUse;
  3638. ULONG BytesAvailable;
  3639. RPC_CHAR ContentLengthString[40]; // enough space for "Content-Length:" + channel lifetime
  3640. BOOL IsInChannel;
  3641. BOOL TestOverrideUsed;
  3642. RPC_CHAR *User;
  3643. RPC_CHAR *Password;
  3644. RPC_CHAR *Domain;
  3645. HANDLE LocalEvent = NULL;
  3646. ULONG SecLevel;
  3647. BOOL LanManHashDisabled;
  3648. ULONG DomainAndUserLength; // length in characters not including null terminator
  3649. ULONG DomainLength; // length in characters not including null terminator
  3650. ULONG UserLength; // length in characters not including null terminator
  3651. RPC_CHAR *DomainAndUserName;
  3652. RPC_CHAR *CurrentPos;
  3653. ULONG HttpProxyLength; // length in characters not including null terminator
  3654. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3655. (ULONG_PTR)ContentLength);
  3656. this->HttpCredentials = HttpCredentials;
  3657. // Open can be called multiple times to send opening requests.
  3658. // Make sure general initialization is done only once.
  3659. if (hSession == NULL)
  3660. {
  3661. ASSERT(hConnect == NULL);
  3662. State = whtcsOpeningRequest;
  3663. ASSERT(Hint->AccessType != rpcpatUnknown);
  3664. if (Hint->AccessType == rpcpatDirect)
  3665. {
  3666. WinHttpAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  3667. UnicodeString = NULL;
  3668. UnicodeStringSize = 0;
  3669. }
  3670. else
  3671. {
  3672. WinHttpAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  3673. // 1 is terminating NULL, 5 is the max port number for a USHORT (65536)
  3674. // and 1 is the column b/n them
  3675. HttpProxyLength = RpcpStringLengthA(Hint->HTTPProxy);
  3676. UnicodeStringSize = HttpProxyLength + 1 + 6;
  3677. UnicodeString = new RPC_CHAR [UnicodeStringSize];
  3678. if (UnicodeString == NULL)
  3679. {
  3680. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3681. RPC_S_OUT_OF_MEMORY);
  3682. return RPC_S_OUT_OF_MEMORY;
  3683. }
  3684. FullAnsiToUnicode(Hint->HTTPProxy, UnicodeString);
  3685. // go to the end of the string and append the port
  3686. CurrentPos = UnicodeString + HttpProxyLength;
  3687. *CurrentPos = ':';
  3688. CurrentPos ++;
  3689. PortNumberToEndpoint(Hint->HTTPProxyPort, CurrentPos);
  3690. }
  3691. // Use WinHttpOpen to obtain a session handle.
  3692. hSession = WinHttpOpenImp( L"MSRPC",
  3693. WinHttpAccessType,
  3694. UnicodeString,
  3695. WINHTTP_NO_PROXY_BYPASS,
  3696. WINHTTP_FLAG_ASYNC
  3697. );
  3698. if (!hSession)
  3699. {
  3700. VALIDATE(GetLastError())
  3701. {
  3702. ERROR_NOT_ENOUGH_MEMORY
  3703. } END_VALIDATE;
  3704. if (UnicodeString)
  3705. delete [] UnicodeString;
  3706. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3707. RPC_S_OUT_OF_MEMORY);
  3708. return RPC_S_OUT_OF_MEMORY;
  3709. }
  3710. // Set the callback to be used by WinHttp to notify us of IO completion.
  3711. WinHttpSetStatusCallbackImp( hSession,
  3712. WinHttpCallback,
  3713. WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
  3714. NULL // Reserved: must be NULL
  3715. );
  3716. // Set the communication timeout.
  3717. HttpResult = WinHttpSetOptionImp( hSession,
  3718. WINHTTP_OPTION_CONNECT_TIMEOUT,
  3719. (LPVOID)&CallTimeout,
  3720. sizeof(ULONG)
  3721. );
  3722. // this function cannot fail unless we give it invalid parameters
  3723. ASSERT(HttpResult == TRUE);
  3724. // Set the send/receive timeout.
  3725. CallTimeout = 30 * 60 * 1000;
  3726. HttpResult = WinHttpSetOptionImp( hSession,
  3727. WINHTTP_OPTION_SEND_TIMEOUT,
  3728. (LPVOID)&CallTimeout,
  3729. sizeof(ULONG)
  3730. );
  3731. // this function cannot fail unless we give it invalid parameters
  3732. ASSERT(HttpResult == TRUE);
  3733. CallTimeout = 30 * 60 * 1000;
  3734. HttpResult = WinHttpSetOptionImp( hSession,
  3735. WINHTTP_OPTION_RECEIVE_TIMEOUT,
  3736. (LPVOID)&CallTimeout,
  3737. sizeof(ULONG)
  3738. );
  3739. // this function cannot fail unless we give it invalid parameters
  3740. ASSERT(HttpResult == TRUE);
  3741. RpcStatus = TopChannel->IsInChannel(&IsInChannel);
  3742. // this cannot fail here. We're opening the channel
  3743. ASSERT(RpcStatus == RPC_S_OK);
  3744. if (IsInChannel && InChannelTargetTestOverride)
  3745. {
  3746. TestOverrideUsed = TRUE;
  3747. UnicodeString = InChannelTargetTestOverride;
  3748. }
  3749. else if (!IsInChannel && OutChannelTargetTestOverride)
  3750. {
  3751. TestOverrideUsed = TRUE;
  3752. UnicodeString = OutChannelTargetTestOverride;
  3753. }
  3754. else
  3755. {
  3756. TestOverrideUsed = FALSE;
  3757. if (Hint->ProxyNameLength + 1 > UnicodeStringSize)
  3758. {
  3759. if (UnicodeString)
  3760. delete [] UnicodeString;
  3761. UnicodeString = new RPC_CHAR [Hint->ProxyNameLength + 1];
  3762. if (UnicodeString == NULL)
  3763. {
  3764. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3765. RPC_S_OUT_OF_MEMORY);
  3766. return RPC_S_OUT_OF_MEMORY;
  3767. }
  3768. }
  3769. FullAnsiToUnicode(Hint->RpcProxy, UnicodeString);
  3770. }
  3771. // Specify an HTTP server to talk to.
  3772. hConnect = WinHttpConnectImp( hSession,
  3773. UnicodeString,
  3774. Hint->RpcProxyPort,
  3775. NULL // Reserved: must be NULL
  3776. );
  3777. if (TestOverrideUsed == FALSE)
  3778. delete [] UnicodeString;
  3779. if (!hConnect)
  3780. {
  3781. VALIDATE(GetLastError())
  3782. {
  3783. ERROR_NOT_ENOUGH_MEMORY
  3784. } END_VALIDATE;
  3785. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3786. RPC_S_OUT_OF_MEMORY);
  3787. return RPC_S_OUT_OF_MEMORY;
  3788. }
  3789. // Create an HTTP Request handle.
  3790. AcceptTypes[0] = AcceptType;
  3791. AcceptTypes[1] = NULL;
  3792. if (HttpCredentials && (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL))
  3793. FlagsToAdd = WINHTTP_FLAG_SECURE;
  3794. else
  3795. FlagsToAdd = 0;
  3796. hRequest = WinHttpOpenRequestImp( hConnect,
  3797. Verb,
  3798. Url,
  3799. NULL, // Version: HTTP/1.1
  3800. WINHTTP_NO_REFERER, // Referer: none
  3801. AcceptTypes, // AcceptTypes: all
  3802. WINHTTP_FLAG_REFRESH | FlagsToAdd // Flags
  3803. );
  3804. if (!hRequest)
  3805. {
  3806. VALIDATE(GetLastError())
  3807. {
  3808. ERROR_NOT_ENOUGH_MEMORY
  3809. } END_VALIDATE;
  3810. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3811. RPC_S_OUT_OF_MEMORY);
  3812. return RPC_S_OUT_OF_MEMORY;
  3813. }
  3814. // Query the optimal read buffer size.
  3815. // We can only query the buffer size from the request handle.
  3816. HttpResult = WinHttpQueryOptionImp( hRequest,
  3817. WINHTTP_OPTION_READ_BUFFER_SIZE,
  3818. (LPVOID)&iPostSize,
  3819. &dwReadBufferSizeSize
  3820. );
  3821. // this cannot fail unless we give it invalid parameters
  3822. ASSERT (HttpResult == TRUE);
  3823. ASSERT(dwReadBufferSizeSize != 0);
  3824. }
  3825. else
  3826. {
  3827. ASSERT(hConnect != NULL);
  3828. ASSERT(hRequest != NULL);
  3829. }
  3830. // do we have a winner? If yes, have we already set the credentials for
  3831. // this scheme? Note that for Basic we need to set them every time.
  3832. if (ChosenAuthScheme
  3833. &&
  3834. (
  3835. (ChosenAuthScheme != CredentialsSetForScheme)
  3836. ||
  3837. (ChosenAuthScheme == RPC_C_HTTP_AUTHN_SCHEME_BASIC)
  3838. )
  3839. )
  3840. {
  3841. // yes. Just use it
  3842. ASSERT(HttpCredentials);
  3843. // we will set the auto logon policy to low (i.e. send NTLM credentials)
  3844. // in two cases. One is if SSL & mutual auth are used. The second is if LM
  3845. // hash is disabled (i.e. the NTLM negotiate leg does not expose user credentials)
  3846. // first, check whether the hash is enabled
  3847. RpcStatus = IsLanManHashDisabled(&LanManHashDisabled);
  3848. if (RpcStatus != RPC_S_OK)
  3849. {
  3850. VALIDATE(RpcStatus)
  3851. {
  3852. RPC_S_OUT_OF_MEMORY
  3853. } END_VALIDATE;
  3854. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3855. RpcStatus);
  3856. return RpcStatus;
  3857. }
  3858. if (
  3859. (
  3860. (HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  3861. &&
  3862. (HttpCredentials->ServerCertificateSubject)
  3863. )
  3864. ||
  3865. (LanManHashDisabled)
  3866. )
  3867. {
  3868. SecLevel = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
  3869. HttpResult = WinHttpSetOptionImp( hRequest,
  3870. WINHTTP_OPTION_AUTOLOGON_POLICY,
  3871. &SecLevel,
  3872. sizeof(ULONG)
  3873. );
  3874. // this function cannot fail unless we give it invalid parameters
  3875. ASSERT(HttpResult == TRUE);
  3876. }
  3877. TransHttpCredentials = I_RpcTransGetHttpCredentials(HttpCredentials);
  3878. if (TransHttpCredentials == NULL)
  3879. {
  3880. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3881. RPC_S_OUT_OF_MEMORY);
  3882. return RPC_S_OUT_OF_MEMORY;
  3883. }
  3884. if (TransHttpCredentials->TransportCredentials)
  3885. {
  3886. User = TransHttpCredentials->TransportCredentials->User;
  3887. Domain = TransHttpCredentials->TransportCredentials->Domain;
  3888. Password = TransHttpCredentials->TransportCredentials->Password;
  3889. DomainLength = RpcpStringLength(Domain);
  3890. UserLength = RpcpStringLength(User);
  3891. // add 1 for '\'
  3892. DomainAndUserLength = DomainLength + 1 + UserLength;
  3893. // add 1 for terminator
  3894. DomainAndUserName = new RPC_CHAR [DomainAndUserLength + 1];
  3895. if (DomainAndUserName == NULL)
  3896. {
  3897. I_RpcTransFreeHttpCredentials(TransHttpCredentials);
  3898. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3899. RPC_S_OUT_OF_MEMORY);
  3900. return RPC_S_OUT_OF_MEMORY;
  3901. }
  3902. RpcpMemoryCopy(DomainAndUserName, Domain, DomainLength * 2);
  3903. DomainAndUserName[DomainLength] = '\\';
  3904. RpcpMemoryCopy(DomainAndUserName + DomainLength + 1, User, UserLength * 2);
  3905. DomainAndUserName[DomainLength + 1 + UserLength] = '\0';
  3906. }
  3907. else
  3908. {
  3909. if (ChosenAuthScheme == RPC_C_HTTP_AUTHN_SCHEME_BASIC)
  3910. {
  3911. // Basic does not support implicit credentials
  3912. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3913. RPC_S_ACCESS_DENIED);
  3914. return RPC_S_ACCESS_DENIED;
  3915. }
  3916. User = NULL;
  3917. Password = NULL;
  3918. DomainAndUserName = NULL;
  3919. }
  3920. HttpResult = WinHttpSetCredentialsImp (hRequest,
  3921. WINHTTP_AUTH_TARGET_SERVER,
  3922. ChosenAuthScheme,
  3923. DomainAndUserName,
  3924. Password,
  3925. NULL
  3926. );
  3927. // success or error, free the domain and user name
  3928. if (DomainAndUserName)
  3929. {
  3930. // technically speaking, we don't have to zero out user and domain name
  3931. // since they are not secret. However, the way the heap works it is likely
  3932. // that they will be next to our credentials, which are not encrypted very
  3933. // strongly. So wipe out the domain and user to prevent an attacker from
  3934. // using them to locate the credentials
  3935. SecureZeroMemory(DomainAndUserName, DomainAndUserLength);
  3936. delete [] DomainAndUserName;
  3937. }
  3938. if (!HttpResult)
  3939. {
  3940. LastError = GetLastError();
  3941. VALIDATE(LastError)
  3942. {
  3943. ERROR_NOT_ENOUGH_MEMORY
  3944. } END_VALIDATE;
  3945. }
  3946. I_RpcTransFreeHttpCredentials(TransHttpCredentials);
  3947. if (!HttpResult)
  3948. {
  3949. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  3950. RPC_S_OUT_OF_MEMORY);
  3951. return RPC_S_OUT_OF_MEMORY;
  3952. }
  3953. // remember that we have already set credentials for this scheme
  3954. CredentialsSetForScheme = ChosenAuthScheme;
  3955. }
  3956. LocalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  3957. if (LocalEvent == NULL)
  3958. {
  3959. RpcStatus = RPC_S_OUT_OF_MEMORY;
  3960. goto CleanupAndExit;
  3961. }
  3962. SyncEvent = LocalEvent;
  3963. LastError = RPC_S_OK;
  3964. // Send a Request.
  3965. if (AdditionalData)
  3966. {
  3967. // if additional data to append, send them immediately
  3968. AdditionalDataLengthToUse = ContentLength;
  3969. ContentLengthToUse = ContentLength;
  3970. }
  3971. else
  3972. {
  3973. AdditionalDataLengthToUse = 0;
  3974. ContentLengthToUse = ContentLength;
  3975. }
  3976. if ((PreviousRequestContentLength != -1) && (ContentLengthToUse != PreviousRequestContentLength))
  3977. {
  3978. // WinHttp normally doesn't update the content-length header if you reuse the
  3979. // request. Do that now.
  3980. RpcpMemoryCopy(ContentLengthString, ContentLengthHeader, sizeof(ContentLengthHeader));
  3981. RpcpItow(ContentLengthToUse, ContentLengthString + (sizeof(ContentLengthHeader) / sizeof(RPC_CHAR)) - 1, 10);
  3982. HttpResult = WinHttpAddRequestHeadersImp (hRequest,
  3983. ContentLengthString,
  3984. -1, // dwHeadersLength - have WinHttp calculate it
  3985. WINHTTP_ADDREQ_FLAG_REPLACE
  3986. );
  3987. if (!HttpResult)
  3988. {
  3989. LastError = GetLastError();
  3990. VALIDATE(LastError)
  3991. {
  3992. ERROR_NOT_ENOUGH_MEMORY
  3993. } END_VALIDATE;
  3994. RpcStatus = LastError;
  3995. goto CleanupAndExit;
  3996. }
  3997. }
  3998. PreviousRequestContentLength = ContentLengthToUse;
  3999. State = whtcsSendingRequest;
  4000. HttpResult = WinHttpSendRequestImp( hRequest,
  4001. WINHTTP_NO_ADDITIONAL_HEADERS, // Additional headers
  4002. 0, // Length of the additional headers
  4003. (LPVOID)AdditionalData, // Optional data to append to the request
  4004. AdditionalDataLengthToUse, // Length of the optional data
  4005. ContentLengthToUse, // Length in bytes of the total data sent
  4006. (DWORD_PTR) this // Application-specified context for this request
  4007. );
  4008. if (!HttpResult)
  4009. {
  4010. SyncEvent = NULL;
  4011. LastError = GetLastError();
  4012. }
  4013. else
  4014. {
  4015. // Sleep waiting for the send request to be completed.
  4016. LastError = WaitForSingleObject(SyncEvent, INFINITE);
  4017. SyncEvent = NULL;
  4018. ASSERT(State == whtcsSentRequest);
  4019. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  4020. LastError = AsyncError;
  4021. AsyncError = RPC_S_INTERNAL_ERROR;
  4022. }
  4023. if (LastError != RPC_S_OK)
  4024. {
  4025. VALIDATE(LastError)
  4026. {
  4027. ERROR_WINHTTP_CANNOT_CONNECT,
  4028. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  4029. ERROR_WINHTTP_CONNECTION_ERROR,
  4030. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4031. ERROR_WINHTTP_INVALID_URL,
  4032. ERROR_WINHTTP_LOGIN_FAILURE,
  4033. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  4034. ERROR_WINHTTP_OUT_OF_HANDLES,
  4035. ERROR_WINHTTP_REDIRECT_FAILED,
  4036. ERROR_WINHTTP_RESEND_REQUEST,
  4037. ERROR_WINHTTP_SECURE_FAILURE,
  4038. ERROR_WINHTTP_SHUTDOWN,
  4039. ERROR_WINHTTP_TIMEOUT,
  4040. ERROR_NOT_ENOUGH_MEMORY,
  4041. ERROR_NOT_SUPPORTED,
  4042. RPC_P_RECEIVE_FAILED,
  4043. RPC_P_SEND_FAILED,
  4044. RPC_S_OUT_OF_MEMORY,
  4045. RPC_S_ACCESS_DENIED,
  4046. ERROR_NO_SYSTEM_RESOURCES,
  4047. ERROR_COMMITMENT_LIMIT,
  4048. ERROR_NOT_ENOUGH_QUOTA
  4049. } END_VALIDATE;
  4050. switch (LastError)
  4051. {
  4052. case ERROR_WINHTTP_CANNOT_CONNECT:
  4053. case ERROR_WINHTTP_CONNECTION_ERROR:
  4054. case ERROR_WINHTTP_INVALID_URL:
  4055. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  4056. case ERROR_WINHTTP_REDIRECT_FAILED:
  4057. case ERROR_WINHTTP_RESEND_REQUEST:
  4058. case ERROR_WINHTTP_SHUTDOWN:
  4059. case RPC_P_RECEIVE_FAILED:
  4060. case RPC_P_SEND_FAILED:
  4061. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  4062. break;
  4063. case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
  4064. case ERROR_WINHTTP_SECURE_FAILURE:
  4065. RpcStatus = RPC_S_ACCESS_DENIED;
  4066. break;
  4067. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  4068. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4069. break;
  4070. case ERROR_WINHTTP_OUT_OF_HANDLES:
  4071. case ERROR_NOT_ENOUGH_MEMORY:
  4072. case RPC_S_OUT_OF_MEMORY:
  4073. case ERROR_NO_SYSTEM_RESOURCES:
  4074. case ERROR_COMMITMENT_LIMIT:
  4075. case ERROR_NOT_ENOUGH_QUOTA :
  4076. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4077. break;
  4078. case ERROR_NOT_SUPPORTED:
  4079. RpcStatus = RPC_S_CANNOT_SUPPORT;
  4080. break;
  4081. case ERROR_WINHTTP_TIMEOUT:
  4082. RpcStatus = RPC_S_CALL_CANCELLED;
  4083. break;
  4084. default:
  4085. // acess denied doesn't get remapped
  4086. ASSERT(LastError == RPC_S_ACCESS_DENIED);
  4087. RpcStatus = LastError;
  4088. break;
  4089. }
  4090. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4091. RpcStatus);
  4092. goto CleanupAndExit;
  4093. }
  4094. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_OPEN, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4095. RPC_S_OK);
  4096. RpcStatus = RPC_S_OK;
  4097. CleanupAndExit:
  4098. if (LocalEvent != NULL)
  4099. CloseHandle(LocalEvent);
  4100. return RpcStatus;
  4101. }
  4102. RPC_STATUS HTTP2WinHttpTransportChannel::Send (
  4103. IN OUT HTTP2SendContext *SendContext
  4104. )
  4105. /*++
  4106. Routine Description:
  4107. Send request
  4108. Arguments:
  4109. SendContext - the send context
  4110. Return Value:
  4111. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  4112. --*/
  4113. {
  4114. BOOL HttpResult = TRUE;
  4115. ULONG LastError;
  4116. RPC_STATUS RpcStatus;
  4117. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4118. (ULONG_PTR)SendContext);
  4119. Mutex.Request();
  4120. SendsPending ++;
  4121. ASSERT(SendsPending >= 0);
  4122. if (SendsPending > 1)
  4123. {
  4124. // queue and exit
  4125. SendContext->SetListEntryUsed();
  4126. RpcpInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  4127. Mutex.Clear();
  4128. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4129. SendsPending);
  4130. return RPC_S_OK;
  4131. }
  4132. Mutex.Clear();
  4133. ASSERT(State == whtcsSentRequest);
  4134. State = whtcsWriting;
  4135. CurrentSendContext = SendContext;
  4136. HttpResult = WinHttpWriteDataImp(hRequest,
  4137. SendContext->pWriteBuffer,
  4138. SendContext->maxWriteBuffer,
  4139. NULL // Number of bytes sent will be provided on async completion.
  4140. );
  4141. if (HttpResult == FALSE)
  4142. {
  4143. // Revert the state if a write could not be posted.
  4144. State = whtcsSentRequest;
  4145. LastError = GetLastError();
  4146. VALIDATE(LastError)
  4147. {
  4148. ERROR_NOT_ENOUGH_MEMORY,
  4149. ERROR_WINHTTP_CONNECTION_ERROR,
  4150. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4151. ERROR_WINHTTP_RESEND_REQUEST,
  4152. ERROR_WINHTTP_SHUTDOWN,
  4153. ERROR_WINHTTP_INTERNAL_ERROR
  4154. } END_VALIDATE;
  4155. RpcStatus = RPC_P_SEND_FAILED;
  4156. }
  4157. else
  4158. RpcStatus = RPC_S_OK;
  4159. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4160. RpcStatus);
  4161. return RpcStatus;
  4162. };
  4163. RPC_STATUS HTTP2WinHttpTransportChannel::Receive (
  4164. IN HTTP2TrafficType TrafficType
  4165. )
  4166. /*++
  4167. Routine Description:
  4168. Receive request
  4169. Arguments:
  4170. TrafficType - the type of traffic we want to receive
  4171. Return Value:
  4172. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  4173. --*/
  4174. {
  4175. BOOL HttpResult;
  4176. ULONG LastError;
  4177. RPC_STATUS RpcStatus;
  4178. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4179. TrafficType);
  4180. //
  4181. // Before we can do any receives, we need to do a WinHttpReceiveResponse
  4182. // if it has not been issued yet.
  4183. //
  4184. // This call only needs to be done before the first Receive.
  4185. //
  4186. if (State != whtcsReceivedResponse)
  4187. {
  4188. Mutex.Request();
  4189. // if there are still sends, we have indicated our
  4190. // traffic type in the DelayedReceiveTrafficType.
  4191. // Just exit, and the last send will do the receive
  4192. // work.
  4193. if (SendsPending > 0)
  4194. {
  4195. if (TrafficType == http2ttRTS)
  4196. DelayedReceiveTrafficType = http2ttRTSWithSpecialBit;
  4197. else if (TrafficType == http2ttData)
  4198. DelayedReceiveTrafficType = http2ttDataWithSpecialBit;
  4199. else
  4200. {
  4201. ASSERT(TrafficType == http2ttRaw);
  4202. DelayedReceiveTrafficType = http2ttRawWithSpecialBit;
  4203. }
  4204. Mutex.Clear();
  4205. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4206. SendsPending);
  4207. return RPC_S_OK;
  4208. }
  4209. Mutex.Clear();
  4210. DelayedReceiveTrafficType = TrafficType;
  4211. ASSERT(State == whtcsSentRequest);
  4212. State = whtcsReceivingResponse;
  4213. HttpResult = WinHttpReceiveResponseImp(hRequest, NULL);
  4214. // If the function returned FALSE, then it has failed syncronously.
  4215. if (!HttpResult)
  4216. {
  4217. DelayedReceiveTrafficType = http2ttNone;
  4218. LastError = GetLastError();
  4219. VALIDATE(LastError)
  4220. {
  4221. ERROR_WINHTTP_CANNOT_CONNECT,
  4222. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  4223. ERROR_WINHTTP_CONNECTION_ERROR,
  4224. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4225. ERROR_WINHTTP_INVALID_URL,
  4226. ERROR_WINHTTP_LOGIN_FAILURE,
  4227. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  4228. ERROR_WINHTTP_OUT_OF_HANDLES,
  4229. ERROR_WINHTTP_REDIRECT_FAILED,
  4230. ERROR_WINHTTP_RESEND_REQUEST,
  4231. ERROR_WINHTTP_SECURE_FAILURE,
  4232. ERROR_WINHTTP_SHUTDOWN,
  4233. ERROR_WINHTTP_TIMEOUT,
  4234. ERROR_NOT_SUPPORTED,
  4235. ERROR_WINHTTP_INTERNAL_ERROR
  4236. } END_VALIDATE;
  4237. switch (LastError)
  4238. {
  4239. case ERROR_WINHTTP_CONNECTION_ERROR:
  4240. case ERROR_WINHTTP_REDIRECT_FAILED:
  4241. case ERROR_WINHTTP_RESEND_REQUEST:
  4242. case ERROR_WINHTTP_SHUTDOWN:
  4243. case ERROR_WINHTTP_SECURE_FAILURE:
  4244. RpcStatus = RPC_P_RECEIVE_FAILED;
  4245. break;
  4246. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  4247. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4248. break;
  4249. case ERROR_NOT_SUPPORTED:
  4250. RpcStatus = RPC_S_CANNOT_SUPPORT;
  4251. break;
  4252. case ERROR_WINHTTP_TIMEOUT:
  4253. RpcStatus = RPC_S_CALL_CANCELLED;
  4254. break;
  4255. default:
  4256. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4257. break;
  4258. }
  4259. VALIDATE(RpcStatus)
  4260. {
  4261. RPC_S_OUT_OF_MEMORY,
  4262. RPC_S_OUT_OF_RESOURCES,
  4263. RPC_P_RECEIVE_FAILED,
  4264. RPC_S_CALL_CANCELLED,
  4265. RPC_P_SEND_FAILED,
  4266. RPC_P_CONNECTION_SHUTDOWN,
  4267. RPC_P_TIMEOUT
  4268. } END_VALIDATE;
  4269. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4270. RpcStatus);
  4271. return RpcStatus;
  4272. }
  4273. else
  4274. {
  4275. // If the function returned TRUE, then it will complete asyncronously.
  4276. // We should return. All additional work will be done on a separate thread
  4277. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4278. RPC_S_OK);
  4279. return RPC_S_OK;
  4280. }
  4281. }
  4282. RpcStatus = HTTP2FragmentReceiver::Receive(TrafficType);
  4283. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4284. RpcStatus);
  4285. return RpcStatus;
  4286. };
  4287. RPC_STATUS HTTP2WinHttpTransportChannel::SendComplete (
  4288. IN RPC_STATUS EventStatus,
  4289. IN OUT HTTP2SendContext *SendContext
  4290. )
  4291. /*++
  4292. Routine Description:
  4293. Send complete notification
  4294. Arguments:
  4295. EventStatus - status of the operation
  4296. SendContext - the send context
  4297. Return Value:
  4298. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  4299. --*/
  4300. {
  4301. HTTP2SendContext *QueuedSendContext;
  4302. LIST_ENTRY *QueuedListEntry;
  4303. ULONG LocalSendsPending;
  4304. BOOL HttpResult;
  4305. ULONG LastError;
  4306. RPC_STATUS RpcStatus;
  4307. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4308. EventStatus);
  4309. CurrentSendContext = NULL;
  4310. Mutex.Request();
  4311. // decrement this in advance so that if we post another send on send
  4312. // complete, it doesn't get queued
  4313. LocalSendsPending = -- SendsPending;
  4314. ASSERT(SendsPending >= 0);
  4315. Mutex.Clear();
  4316. // If we are processing a failed send-complete, this call may abort
  4317. // the channels and complete pending sends.
  4318. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  4319. if ((EventStatus == RPC_S_OK)
  4320. || (EventStatus == RPC_P_PACKET_CONSUMED) )
  4321. {
  4322. QueuedSendContext = NULL;
  4323. // Check if we have a queued send context.
  4324. // Because we pre-decremented SendsPending, we have "borrowed"
  4325. // a count and there is a queued context iff the count is above 0.
  4326. if (LocalSendsPending > 0)
  4327. {
  4328. Mutex.Request();
  4329. QueuedListEntry = RpcpRemoveHeadList(&BufferQueueHead);
  4330. ASSERT(QueuedListEntry);
  4331. ASSERT(QueuedListEntry != &BufferQueueHead);
  4332. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  4333. Mutex.Clear();
  4334. QueuedSendContext->SetListEntryUnused();
  4335. }
  4336. if (QueuedSendContext)
  4337. {
  4338. ASSERT(State == whtcsSentRequest);
  4339. State = whtcsWriting;
  4340. // need to synchronize with aborts (rule 9)
  4341. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4342. CurrentSendContext = QueuedSendContext;
  4343. NumberOfBytesTransferred = QueuedSendContext->maxWriteBuffer;
  4344. if (RpcStatus == RPC_S_OK)
  4345. {
  4346. HttpResult = WinHttpWriteDataImp(hRequest,
  4347. QueuedSendContext->pWriteBuffer,
  4348. QueuedSendContext->maxWriteBuffer,
  4349. NULL // Number of bytes sent will be provided on async completion.
  4350. );
  4351. TopChannel->FinishSubmitAsync();
  4352. if (HttpResult == FALSE)
  4353. {
  4354. // Revert the state if a write could not be posted.
  4355. State = whtcsSentRequest;
  4356. LastError = GetLastError();
  4357. VALIDATE(LastError)
  4358. {
  4359. ERROR_WINHTTP_CONNECTION_ERROR,
  4360. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4361. ERROR_WINHTTP_RESEND_REQUEST,
  4362. ERROR_WINHTTP_SHUTDOWN
  4363. } END_VALIDATE;
  4364. // the send failed. We don't get a notification for it
  4365. // so we must issue one. We do this by posting direct send
  4366. AsyncError = RPC_P_SEND_FAILED;
  4367. ASSERT(CurrentSendContext == QueuedSendContext);
  4368. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  4369. this
  4370. );
  4371. }
  4372. else
  4373. {
  4374. // nothing to do - notification will come asynchronously
  4375. }
  4376. }
  4377. else
  4378. {
  4379. // Revert the state if a write could not be posted.
  4380. State = whtcsSentRequest;
  4381. AsyncError = RPC_P_SEND_FAILED;
  4382. ASSERT(CurrentSendContext == QueuedSendContext);
  4383. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_SEND,
  4384. this
  4385. );
  4386. }
  4387. }
  4388. }
  4389. // if a receive has registered itself and we're the one who finished the
  4390. // sends, do the receive
  4391. if (
  4392. (
  4393. (DelayedReceiveTrafficType == http2ttRTSWithSpecialBit)
  4394. || (DelayedReceiveTrafficType == http2ttDataWithSpecialBit)
  4395. || (DelayedReceiveTrafficType == http2ttRawWithSpecialBit)
  4396. )
  4397. &&
  4398. (LocalSendsPending == 0)
  4399. )
  4400. {
  4401. if (DelayedReceiveTrafficType == http2ttRTSWithSpecialBit)
  4402. DelayedReceiveTrafficType = http2ttRTS;
  4403. else if (DelayedReceiveTrafficType == http2ttRawWithSpecialBit)
  4404. DelayedReceiveTrafficType = http2ttRaw;
  4405. else
  4406. {
  4407. ASSERT(DelayedReceiveTrafficType == http2ttDataWithSpecialBit);
  4408. DelayedReceiveTrafficType = http2ttData;
  4409. }
  4410. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4411. if (RpcStatus == RPC_S_OK)
  4412. {
  4413. RpcStatus = Receive(DelayedReceiveTrafficType);
  4414. TopChannel->FinishSubmitAsync();
  4415. }
  4416. if (RpcStatus != RPC_S_OK)
  4417. {
  4418. // offload the result as direct receive. We use the refcount of the receive
  4419. // to complete the operation on the worker thread.
  4420. AsyncError = RpcStatus;
  4421. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  4422. this
  4423. );
  4424. }
  4425. else
  4426. {
  4427. // when it completes, it will issue its own notification
  4428. }
  4429. }
  4430. // don't call AsyncCompleteHelper here. We will always be called from DirectSendComplete
  4431. // which will call AsyncCompleteHelper for us
  4432. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4433. EventStatus);
  4434. return EventStatus;
  4435. }
  4436. //
  4437. // WinHttpCloseHandle may return failure in low-memory conditions.
  4438. // We will just re-try several times and record that a handle has been leaked.
  4439. // We should remove this code when:
  4440. // 647932 WinHttpCloseHandle fails in low memory conditions
  4441. // is fixed.
  4442. //
  4443. unsigned int nWinHttpHandlesLeaked = 0;
  4444. void HTTP2WinHttpTransportChannel::TryClosingWinHttpHandle (
  4445. IN HINTERNET *pHandle
  4446. )
  4447. /*++
  4448. Routine Description:
  4449. Tries to close a WinHttp handle.
  4450. Arguments:
  4451. hHandle - Pointer to a handle to close. Handle is set to NULL after lcosing.
  4452. --*/
  4453. {
  4454. BOOL HttpResult;
  4455. unsigned int nRetries = 10;
  4456. do
  4457. {
  4458. HttpResult = WinHttpCloseHandleImp(*pHandle);
  4459. if (!HttpResult)
  4460. {
  4461. nRetries--;
  4462. Sleep (10);
  4463. }
  4464. }
  4465. while (!HttpResult && nRetries > 0);
  4466. if (nRetries == 0)
  4467. {
  4468. nWinHttpHandlesLeaked++;
  4469. }
  4470. *pHandle = NULL;
  4471. }
  4472. void HTTP2WinHttpTransportChannel::Abort (
  4473. IN RPC_STATUS RpcStatus
  4474. )
  4475. /*++
  4476. Routine Description:
  4477. Abort the channel
  4478. Arguments:
  4479. RpcStatus - the error code with which we abort
  4480. Return Value:
  4481. Notes:
  4482. This method must be idempotent. It may be called multiple times.
  4483. --*/
  4484. {
  4485. HTTP2SendContext *QueuedSendContext;
  4486. LIST_ENTRY *QueuedListEntry;
  4487. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_WINHTTP_CHANNEL, RpcStatus);
  4488. if (hRequest)
  4489. {
  4490. TryClosingWinHttpHandle(&hRequest);
  4491. }
  4492. if (hConnect)
  4493. {
  4494. TryClosingWinHttpHandle(&hConnect);
  4495. }
  4496. if (hSession)
  4497. {
  4498. TryClosingWinHttpHandle(&hSession);
  4499. }
  4500. Mutex.Request();
  4501. // If there are more then 1 pending sends, then some sends must have been queued.
  4502. // We will abort the queued sends.
  4503. for (; SendsPending > 1; )
  4504. {
  4505. ASSERT(!RpcpIsListEmpty(&BufferQueueHead));
  4506. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  4507. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  4508. -- SendsPending;
  4509. ASSERT(SendsPending > 0);
  4510. HTTP2TransportChannel::SendComplete(RpcStatus, QueuedSendContext);
  4511. AsyncCompleteHelper(RpcStatus);
  4512. }
  4513. Mutex.Clear();
  4514. }
  4515. void HTTP2WinHttpTransportChannel::FreeObject (
  4516. void
  4517. )
  4518. /*++
  4519. Routine Description:
  4520. Frees the object. Acts like a destructor for the
  4521. channel.
  4522. Arguments:
  4523. Return Value:
  4524. --*/
  4525. {
  4526. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_WINHTTP_CHANNEL, 0);
  4527. if (pReadBuffer)
  4528. {
  4529. RpcFreeBuffer(pReadBuffer);
  4530. pReadBuffer = NULL;
  4531. }
  4532. HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  4533. }
  4534. RPC_STATUS HTTP2WinHttpTransportChannel::DirectReceiveComplete (
  4535. OUT BYTE **ReceivedBuffer,
  4536. OUT ULONG *ReceivedBufferLength,
  4537. OUT void **RuntimeConnection
  4538. )
  4539. /*++
  4540. Routine Description:
  4541. Direct receive completion (i.e. we posted a receive
  4542. to ourselves)
  4543. Arguments:
  4544. ReceivedBuffer - the buffer that we received.
  4545. ReceivedBufferLength - the length of the received
  4546. buffer
  4547. RuntimeConnection - the connection to return to the runtime
  4548. if the packet is not consumed.
  4549. Return Value:
  4550. RPC_S_OK, RPC_P_PACKET_CONSUMED or RPC_S_* errors.
  4551. --*/
  4552. {
  4553. RPC_STATUS RpcStatus;
  4554. BOOL HttpResult;
  4555. ULONG WaitResult;
  4556. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4557. AsyncError);
  4558. *RuntimeConnection = TopChannel->GetRuntimeConnection();
  4559. // two cases - previous coalesced read and a real read
  4560. if (iLastRead && iLastRead == MaxReadBuffer)
  4561. {
  4562. // previous coalesced read
  4563. *ReceivedBufferLength = MaxReadBuffer;
  4564. iLastRead = 0;
  4565. RpcStatus = RPC_S_OK;
  4566. }
  4567. else
  4568. {
  4569. // real read
  4570. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  4571. if ((AsyncError == RPC_S_OK)
  4572. && (NumberOfBytesTransferred == 0))
  4573. {
  4574. // zero bytes transferred indicates end of request.
  4575. AsyncError = RPC_P_RECEIVE_FAILED;
  4576. }
  4577. RpcStatus = AsyncError;
  4578. AsyncError = RPC_S_INTERNAL_ERROR;
  4579. if (RpcStatus == RPC_S_OK)
  4580. {
  4581. if (pReadBuffer == NULL)
  4582. {
  4583. if (NumberOfBytesTransferred > iPostSize)
  4584. MaxReadBuffer = NumberOfBytesTransferred;
  4585. else
  4586. MaxReadBuffer = iPostSize;
  4587. pReadBuffer = (BYTE *)RpcAllocateBuffer(MaxReadBuffer);
  4588. // fall through for error check below
  4589. }
  4590. else if (MaxReadBuffer - iLastRead < NumberOfBytesTransferred)
  4591. {
  4592. ASSERT(iLastRead < MaxReadBuffer);
  4593. // Buffer too small for the message.
  4594. RpcStatus = TransConnectionReallocPacket(NULL,
  4595. &pReadBuffer,
  4596. iLastRead,
  4597. iLastRead + NumberOfBytesTransferred
  4598. );
  4599. if (RpcStatus != RPC_S_OK)
  4600. {
  4601. RpcFreeBuffer(pReadBuffer);
  4602. pReadBuffer = NULL;
  4603. }
  4604. MaxReadBuffer = iLastRead + NumberOfBytesTransferred;
  4605. }
  4606. else
  4607. {
  4608. // buffer should be enough - no need to reallocate
  4609. ASSERT(iLastRead < MaxReadBuffer);
  4610. }
  4611. if (pReadBuffer == NULL)
  4612. {
  4613. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4614. NumberOfBytesTransferred = 0;
  4615. }
  4616. else
  4617. {
  4618. // we need to temporarily get into submission context to synchronize
  4619. // with Aborts
  4620. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4621. if (RpcStatus == RPC_S_OK)
  4622. {
  4623. ASSERT(SyncEvent == NULL);
  4624. SyncEvent = I_RpcTransGetThreadEvent();
  4625. ResetEvent(SyncEvent);
  4626. HttpResult = WinHttpReadDataImp(hRequest,
  4627. pReadBuffer + iLastRead,
  4628. NumberOfBytesTransferred,
  4629. NULL // Number of bytes read will be provided on async completion.
  4630. );
  4631. // wait for read complete to finish
  4632. WaitResult = WaitForSingleObject(SyncEvent, INFINITE);
  4633. // this cannot fail
  4634. ASSERT(WaitResult == WAIT_OBJECT_0);
  4635. SyncEvent = NULL;
  4636. // the data are available. We cannot possibly fail
  4637. ASSERT(HttpResult);
  4638. TopChannel->FinishSubmitAsync();
  4639. VALIDATE (AsyncError)
  4640. {
  4641. RPC_P_RECEIVE_FAILED,
  4642. RPC_S_OK
  4643. } END_VALIDATE;
  4644. RpcStatus = AsyncError;
  4645. AsyncError = RPC_S_INTERNAL_ERROR;
  4646. // fall through with the status
  4647. }
  4648. else
  4649. {
  4650. // fall through with the error.
  4651. }
  4652. }
  4653. }
  4654. *ReceivedBufferLength = NumberOfBytesTransferred;
  4655. }
  4656. RpcStatus = HTTP2WinHttpTransportChannel::ReceiveComplete(RpcStatus,
  4657. http2ttRaw,
  4658. ReceivedBuffer,
  4659. (UINT *)ReceivedBufferLength
  4660. );
  4661. // did we receive an incomplete buffer?
  4662. if ((RpcStatus == RPC_S_OK) && (*ReceivedBuffer == NULL))
  4663. {
  4664. // hide it from the runtime
  4665. RpcStatus = RPC_P_PACKET_CONSUMED;
  4666. }
  4667. // AsyncCompleteHelper has already been called in ReceiveComplete
  4668. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4669. RpcStatus);
  4670. return RpcStatus;
  4671. }
  4672. RPC_STATUS HTTP2WinHttpTransportChannel::DirectSendComplete (
  4673. OUT BYTE **SentBuffer,
  4674. OUT void **SendContext
  4675. )
  4676. /*++
  4677. Routine Description:
  4678. Direct send complete notification. Complete the send
  4679. passing it only through channels that have seen it (i.e.
  4680. above us).
  4681. Arguments:
  4682. SentBuffer - on output the buffer that we tried to send
  4683. SendContext - on output contains the send context as
  4684. seen by the runtime
  4685. Return Value:
  4686. RPC_S_OK to return error to runtime
  4687. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  4688. RPC_S_* error - return error to runtime
  4689. --*/
  4690. {
  4691. HTTP2SendContext *LocalCurrentSendContext;
  4692. RPC_STATUS RpcStatus;
  4693. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4694. AsyncError);
  4695. ASSERT(AsyncError != RPC_S_INTERNAL_ERROR);
  4696. ASSERT(CurrentSendContext);
  4697. State = whtcsSentRequest;
  4698. LocalCurrentSendContext = CurrentSendContext;
  4699. // CurrentSendContext is zeroed out by the call.
  4700. RpcStatus = HTTP2WinHttpTransportChannel::SendComplete(AsyncError, LocalCurrentSendContext);
  4701. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  4702. {
  4703. // this will return to the runtime. Make sure it is valid
  4704. I_RpcTransVerifyClientRuntimeCallFromContext(LocalCurrentSendContext);
  4705. *SendContext = LocalCurrentSendContext;
  4706. *SentBuffer = LocalCurrentSendContext->pWriteBuffer;
  4707. }
  4708. else
  4709. {
  4710. // the packet was a transport packet - it won't be seen by the runtime
  4711. *SendContext = NULL;
  4712. *SentBuffer = NULL;
  4713. }
  4714. RpcStatus = AsyncCompleteHelper(RpcStatus);
  4715. // do not touch this pointer after here unless the list was not-empty
  4716. // (which implies we still have refcounts)
  4717. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4718. RpcStatus);
  4719. return RpcStatus;
  4720. }
  4721. void HTTP2WinHttpTransportChannel::DelayedReceive (
  4722. void
  4723. )
  4724. /*++
  4725. Routine Description:
  4726. Performs a delayed receive. The first receive on an WinHttp
  4727. channel is delayed because we must receive the headers before
  4728. we can do the actual receive.
  4729. Arguments:
  4730. Return Value:
  4731. Note: Will be called from upcall context
  4732. --*/
  4733. {
  4734. BOOL HttpResult;
  4735. ULONG LastError;
  4736. RPC_STATUS RpcStatus;
  4737. BOOL InSubmissionContext;
  4738. BYTE *Ignored;
  4739. UINT BufferLength;
  4740. ULONG StatusCode;
  4741. ULONG StatusCodeLength;
  4742. ULONG HttpStatus;
  4743. RPC_CHAR ConnectionOptions[40];
  4744. RPC_CHAR *ConnectionOptionsToUse;
  4745. ULONG ConnectionOptionsLength;
  4746. int i;
  4747. RPC_CHAR *KeepAliveString;
  4748. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_WHTTP_DELAYED_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  4749. AsyncError);
  4750. // Check if we have received an async failure.
  4751. LastError = AsyncError;
  4752. AsyncError = RPC_S_INTERNAL_ERROR;
  4753. RpcStatus = RPC_S_OK;
  4754. InSubmissionContext = FALSE;
  4755. if (LastError == RPC_S_OK)
  4756. {
  4757. // get into submission context
  4758. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  4759. if (RpcStatus == RPC_S_OK)
  4760. {
  4761. InSubmissionContext = TRUE;
  4762. StatusCodeLength = sizeof(StatusCode);
  4763. HttpResult = WinHttpQueryHeadersImp (
  4764. hRequest,
  4765. WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
  4766. WINHTTP_HEADER_NAME_BY_INDEX,
  4767. &StatusCode,
  4768. &StatusCodeLength,
  4769. WINHTTP_NO_HEADER_INDEX
  4770. );
  4771. if (!HttpResult)
  4772. {
  4773. LastError = GetLastError();
  4774. }
  4775. else
  4776. {
  4777. if (StatusCode != HTTP_STATUS_OK)
  4778. {
  4779. if ((StatusCode >= RPC_S_INVALID_STRING_BINDING) && (StatusCode <= RPC_X_BAD_STUB_DATA))
  4780. {
  4781. // if it is an RPC error code, just return it.
  4782. RpcStatus = StatusCode;
  4783. }
  4784. else if ((StatusCode == HTTP_STATUS_NOT_FOUND)
  4785. || (StatusCode == HTTP_STATUS_BAD_METHOD)
  4786. || (StatusCode == HTTP_STATUS_BAD_METHOD)
  4787. || (StatusCode == HTTP_STATUS_SERVER_ERROR)
  4788. || (StatusCode == HTTP_STATUS_NOT_SUPPORTED)
  4789. || (StatusCode == HTTP_STATUS_SERVICE_UNAVAIL) )
  4790. {
  4791. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  4792. }
  4793. else if (StatusCode == HTTP_STATUS_REQUEST_TOO_LARGE)
  4794. RpcStatus = RPC_S_SERVER_OUT_OF_MEMORY;
  4795. else if (StatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
  4796. {
  4797. if ((HttpCredentials == NULL)
  4798. || (HttpCredentials->AuthenticationTarget & RPC_C_HTTP_AUTHN_TARGET_PROXY) == 0)
  4799. {
  4800. // we were not asked to authenticate against a proxy. Just fail
  4801. RpcStatus = RPC_S_ACCESS_DENIED;
  4802. }
  4803. else
  4804. {
  4805. ChosenAuthScheme = NegotiateAuthScheme();
  4806. if (ChosenAuthScheme == 0)
  4807. RpcStatus = RPC_S_ACCESS_DENIED;
  4808. else
  4809. {
  4810. State = whtcsDraining;
  4811. HttpResult = WinHttpQueryDataAvailableImp(hRequest,
  4812. NULL // Number of bytes available will be provided on async completion.
  4813. );
  4814. ASSERT(HttpResult);
  4815. RpcStatus = RPC_S_OK;
  4816. goto CleanupAndExit;
  4817. }
  4818. }
  4819. }
  4820. else if (StatusCode == HTTP_STATUS_DENIED)
  4821. {
  4822. if ((HttpCredentials == NULL)
  4823. || (HttpCredentials->AuthenticationTarget & RPC_C_HTTP_AUTHN_TARGET_SERVER) == 0)
  4824. {
  4825. // we were not asked to authenticate against a server. Just fail
  4826. RpcStatus = RPC_S_ACCESS_DENIED;
  4827. }
  4828. else
  4829. {
  4830. ChosenAuthScheme = NegotiateAuthScheme();
  4831. if (ChosenAuthScheme == 0)
  4832. RpcStatus = RPC_S_ACCESS_DENIED;
  4833. else
  4834. {
  4835. State = whtcsDraining;
  4836. HttpResult = WinHttpQueryDataAvailableImp(hRequest,
  4837. NULL // Number of bytes available will be provided on async completion.
  4838. );
  4839. ASSERT(HttpResult);
  4840. RpcStatus = RPC_S_OK;
  4841. goto CleanupAndExit;
  4842. }
  4843. }
  4844. }
  4845. else
  4846. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4847. }
  4848. else
  4849. {
  4850. // RpcStatus is already set above
  4851. ASSERT(RpcStatus == RPC_S_OK);
  4852. ConnectionOptionsLength = sizeof(ConnectionOptions);
  4853. ConnectionOptionsToUse = ConnectionOptions;
  4854. for (i = 0; i < 2; i ++)
  4855. {
  4856. HttpResult = WinHttpQueryHeadersImp (
  4857. hRequest,
  4858. WINHTTP_QUERY_CONNECTION,
  4859. WINHTTP_HEADER_NAME_BY_INDEX,
  4860. ConnectionOptionsToUse,
  4861. &ConnectionOptionsLength,
  4862. WINHTTP_NO_HEADER_INDEX
  4863. );
  4864. if (!HttpResult)
  4865. {
  4866. LastError = GetLastError();
  4867. if (LastError == ERROR_INSUFFICIENT_BUFFER)
  4868. {
  4869. ConnectionOptionsToUse = new RPC_CHAR[ConnectionOptionsLength];
  4870. if (ConnectionOptionsToUse == NULL)
  4871. {
  4872. LastError = RPC_S_OUT_OF_MEMORY;
  4873. // fall through with the error below
  4874. break;
  4875. }
  4876. }
  4877. else if (LastError == ERROR_WINHTTP_HEADER_NOT_FOUND)
  4878. {
  4879. // we did not get keep alives. This is ok
  4880. LastError = RPC_S_OK;
  4881. KeepAlive = FALSE;
  4882. break;
  4883. }
  4884. else
  4885. {
  4886. LastError = RPC_S_OUT_OF_MEMORY;
  4887. // fall through with the error below
  4888. break;
  4889. }
  4890. }
  4891. else
  4892. {
  4893. LastError = RPC_S_OK;
  4894. break;
  4895. }
  4896. } // for (i ...
  4897. ASSERT(LastError != ERROR_INSUFFICIENT_BUFFER);
  4898. if (LastError == RPC_S_OK)
  4899. {
  4900. // we got the connection options. Do we have keep alive?
  4901. KeepAliveString = RpcpStrStr(ConnectionOptionsToUse, L"Keep-Alive");
  4902. if (KeepAliveString)
  4903. KeepAlive = TRUE;
  4904. }
  4905. if (ConnectionOptionsToUse != ConnectionOptions)
  4906. delete [] ConnectionOptionsToUse;
  4907. } // StatusCode == HTTP_STATUS_OK
  4908. } // WinHttpQueryHeadersImp succeeded
  4909. } // BeginSimpleSubmitAsync succeeded
  4910. else
  4911. {
  4912. // BeginSimpleSubmitAsync failed - fall through with the error
  4913. // RpcStatus and success LastError
  4914. ASSERT(LastError == RPC_S_OK);
  4915. }
  4916. }
  4917. if (LastError != RPC_S_OK)
  4918. {
  4919. VALIDATE(LastError)
  4920. {
  4921. ERROR_WINHTTP_CANNOT_CONNECT,
  4922. ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED,
  4923. ERROR_WINHTTP_CONNECTION_ERROR,
  4924. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  4925. ERROR_WINHTTP_INVALID_URL,
  4926. ERROR_WINHTTP_LOGIN_FAILURE,
  4927. ERROR_WINHTTP_NAME_NOT_RESOLVED,
  4928. ERROR_WINHTTP_OUT_OF_HANDLES,
  4929. ERROR_WINHTTP_REDIRECT_FAILED,
  4930. ERROR_WINHTTP_RESEND_REQUEST,
  4931. ERROR_WINHTTP_SECURE_FAILURE,
  4932. ERROR_WINHTTP_SHUTDOWN,
  4933. ERROR_WINHTTP_TIMEOUT,
  4934. ERROR_NOT_SUPPORTED,
  4935. RPC_P_SEND_FAILED,
  4936. RPC_P_RECEIVE_FAILED,
  4937. RPC_P_AUTH_NEEDED
  4938. } END_VALIDATE;
  4939. switch (LastError)
  4940. {
  4941. case ERROR_WINHTTP_CONNECTION_ERROR:
  4942. case ERROR_WINHTTP_REDIRECT_FAILED:
  4943. case ERROR_WINHTTP_RESEND_REQUEST:
  4944. case ERROR_WINHTTP_SHUTDOWN:
  4945. case ERROR_WINHTTP_CANNOT_CONNECT:
  4946. case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
  4947. case ERROR_WINHTTP_INVALID_URL:
  4948. case ERROR_WINHTTP_LOGIN_FAILURE:
  4949. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  4950. case ERROR_WINHTTP_SECURE_FAILURE:
  4951. case RPC_P_AUTH_NEEDED:
  4952. RpcStatus = RPC_P_RECEIVE_FAILED;
  4953. break;
  4954. case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
  4955. RpcStatus = RPC_S_PROTOCOL_ERROR;
  4956. break;
  4957. case ERROR_NOT_SUPPORTED:
  4958. RpcStatus = RPC_S_CANNOT_SUPPORT;
  4959. break;
  4960. case ERROR_WINHTTP_TIMEOUT:
  4961. RpcStatus = RPC_S_CALL_CANCELLED;
  4962. break;
  4963. case RPC_P_SEND_FAILED:
  4964. case RPC_P_RECEIVE_FAILED:
  4965. RpcStatus = LastError;
  4966. break;
  4967. default:
  4968. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4969. break;
  4970. }
  4971. VALIDATE(RpcStatus)
  4972. {
  4973. RPC_S_OUT_OF_MEMORY,
  4974. RPC_S_OUT_OF_RESOURCES,
  4975. RPC_P_RECEIVE_FAILED,
  4976. RPC_S_CALL_CANCELLED,
  4977. RPC_P_SEND_FAILED,
  4978. RPC_P_CONNECTION_SHUTDOWN,
  4979. RPC_P_TIMEOUT
  4980. } END_VALIDATE;
  4981. }
  4982. if (RpcStatus == RPC_S_OK)
  4983. {
  4984. ASSERT(InSubmissionContext);
  4985. RpcStatus = HTTP2FragmentReceiver::Receive(DelayedReceiveTrafficType);
  4986. }
  4987. CleanupAndExit:
  4988. if (InSubmissionContext)
  4989. {
  4990. TopChannel->FinishSubmitAsync();
  4991. }
  4992. DelayedReceiveTrafficType = http2ttNone;
  4993. if (RpcStatus != RPC_S_OK)
  4994. {
  4995. // we got a failure. Issue receive complete. Since DelayedReceive
  4996. // happens only on channel recycling, and then we know we
  4997. // issue RTS receive, we don't need to indicate this to the runtime
  4998. BufferLength = 0;
  4999. RpcStatus = ReceiveComplete(RpcStatus,
  5000. DelayedReceiveTrafficType,
  5001. &Ignored,
  5002. &BufferLength
  5003. );
  5004. ASSERT(RpcStatus == RPC_P_PACKET_CONSUMED);
  5005. }
  5006. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_WHTTP_DELAYED_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL,
  5007. RpcStatus);
  5008. }
  5009. void HTTP2WinHttpTransportChannel::VerifyServerCredentials (
  5010. void
  5011. )
  5012. /*++
  5013. Routine Description:
  5014. Verifies that the server credentials match the subject info we
  5015. were given.
  5016. Arguments:
  5017. Return Value:
  5018. --*/
  5019. {
  5020. BOOL HttpResult;
  5021. PCERT_CONTEXT CertContext;
  5022. ULONG OptionSize;
  5023. RPC_STATUS RpcStatus;
  5024. RPC_CHAR *StringSPN;
  5025. RPC_STATUS AbortError;
  5026. // make sure nobody has touched the async error after open
  5027. ASSERT((AsyncError == RPC_S_OK)
  5028. || ((AsyncError == RPC_S_INTERNAL_ERROR)));
  5029. // if no credentials, nothing to verify
  5030. if ((HttpCredentials == NULL)
  5031. || (HttpCredentials->ServerCertificateSubject == NULL))
  5032. return;
  5033. OptionSize = sizeof(PCERT_CONTEXT);
  5034. HttpResult = WinHttpQueryOptionImp(hRequest,
  5035. WINHTTP_OPTION_SERVER_CERT_CONTEXT,
  5036. &CertContext,
  5037. &OptionSize
  5038. );
  5039. if (!HttpResult)
  5040. {
  5041. AsyncError = GetLastError();
  5042. VALIDATE(AsyncError)
  5043. {
  5044. ERROR_NOT_ENOUGH_MEMORY,
  5045. ERROR_INVALID_OPERATION
  5046. } END_VALIDATE;
  5047. switch (AsyncError)
  5048. {
  5049. case ERROR_INVALID_OPERATION:
  5050. // we will get this when we ask for the certificate of non
  5051. // SSL connection
  5052. AsyncError = RPC_S_ACCESS_DENIED;
  5053. break;
  5054. default:
  5055. AbortError = RPC_S_OUT_OF_MEMORY;
  5056. }
  5057. goto AbortAndExit;
  5058. }
  5059. RpcStatus = I_RpcTransCertMatchPrincipalName(CertContext, HttpCredentials->ServerCertificateSubject);
  5060. if (RpcStatus != RPC_S_OK)
  5061. {
  5062. AbortError = AsyncError = RpcStatus;
  5063. goto AbortAndExit;
  5064. }
  5065. return;
  5066. AbortAndExit:
  5067. ASSERT(AsyncError != ERROR_SUCCESS);
  5068. // HTTP2WinHttpTransportChannel::Abort is idempotent. We'll call it now to
  5069. // tell WinHttp to abort, and ClientOpen will call it again. This is ok.
  5070. Abort(AbortError);
  5071. }
  5072. RPC_STATUS HTTP2WinHttpTransportChannel::PostReceive (
  5073. void
  5074. )
  5075. /*++
  5076. Routine Description:
  5077. Posts a receive to WinHttp.
  5078. Arguments:
  5079. Return Value:
  5080. RPC_S_OK or RPC_S_* error
  5081. Note: May be called from both submission and upcall context
  5082. --*/
  5083. {
  5084. BOOL HttpResult;
  5085. RPC_STATUS RpcStatus;
  5086. ULONG LastError;
  5087. ULONG AvailableLength;
  5088. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL, 0);
  5089. ASSERT(State == whtcsReceivedResponse);
  5090. State = whtcsReading;
  5091. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  5092. if (RpcStatus != RPC_S_OK)
  5093. {
  5094. // Revert the state if a read could not be posted.
  5095. State = whtcsReceivedResponse;
  5096. return RpcStatus;
  5097. }
  5098. HttpResult = WinHttpQueryDataAvailableImp (hRequest,
  5099. NULL // Number of bytes available will be provided on async completion.
  5100. );
  5101. TopChannel->FinishSubmitAsync();
  5102. if (!HttpResult)
  5103. {
  5104. LastError = GetLastError();
  5105. VALIDATE(LastError)
  5106. {
  5107. ERROR_NOT_ENOUGH_MEMORY,
  5108. ERROR_WINHTTP_CONNECTION_ERROR,
  5109. ERROR_WINHTTP_INVALID_SERVER_RESPONSE,
  5110. ERROR_WINHTTP_RESEND_REQUEST,
  5111. ERROR_WINHTTP_SHUTDOWN
  5112. } END_VALIDATE;
  5113. // Revert the state if a read could not be posted.
  5114. State = whtcsReceivedResponse;
  5115. RpcStatus = RPC_P_RECEIVE_FAILED;
  5116. }
  5117. else
  5118. {
  5119. // If the function returned non-zero,
  5120. // then it will complete asyncronously.
  5121. // Nothing to do here, we will receive async notification.
  5122. RpcStatus = RPC_S_OK;
  5123. }
  5124. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_WINHTTP_CHANNEL, RpcStatus);
  5125. return RpcStatus;
  5126. }
  5127. ULONG HTTP2WinHttpTransportChannel::GetPostRuntimeEvent (
  5128. void
  5129. )
  5130. /*++
  5131. Routine Description:
  5132. Gets the message to be posted to the runtime.
  5133. Arguments:
  5134. Return Value:
  5135. The message to post to the runtime
  5136. --*/
  5137. {
  5138. return HTTP2_WINHTTP_DIRECT_RECV;
  5139. }
  5140. ULONG HTTP2WinHttpTransportChannel::NegotiateAuthScheme (
  5141. void
  5142. )
  5143. /*++
  5144. Routine Description:
  5145. Negotiates an auth scheme supported by client and server/proxy
  5146. according to preference rules.
  5147. Arguments:
  5148. Return Value:
  5149. The negotiated scheme or 0 if no scheme could be negotiated.
  5150. Notes:
  5151. The actual server/proxy supported/preferred schemes will be retrieved
  5152. from hRequest.
  5153. --*/
  5154. {
  5155. BOOL HttpResult;
  5156. ULONG Ignored;
  5157. ULONG ServerSupportedSchemes; // we use Server for brevity, but this
  5158. ULONG ServerPreferredScheme; // applies to proxies as well
  5159. ULONG *ClientSupportedSchemes;
  5160. ULONG CountOfClientSupportedSchemes;
  5161. int i;
  5162. HttpResult = WinHttpQueryAuthSchemesImp (hRequest,
  5163. &ServerSupportedSchemes,
  5164. &ServerPreferredScheme,
  5165. &Ignored // pdwAuthTarget - we have already determined this
  5166. // from the error code - ignore now.
  5167. );
  5168. if (!HttpResult)
  5169. return 0;
  5170. // first, if we support the server preference, we just choose
  5171. // that.
  5172. CountOfClientSupportedSchemes = HttpCredentials->NumberOfAuthnSchemes;
  5173. ClientSupportedSchemes = HttpCredentials->AuthnSchemes;
  5174. ASSERT(CountOfClientSupportedSchemes > 0);
  5175. ASSERT(ClientSupportedSchemes != NULL);
  5176. for (i = 0; i < CountOfClientSupportedSchemes; i ++)
  5177. {
  5178. if (ServerPreferredScheme == ClientSupportedSchemes[i])
  5179. return ServerPreferredScheme;
  5180. }
  5181. // client doesn't support what the server asks for. Try whether the server
  5182. // supports what the client prefers
  5183. for (i = 0; i < CountOfClientSupportedSchemes; i ++)
  5184. {
  5185. if (ServerSupportedSchemes & ClientSupportedSchemes[i])
  5186. return ClientSupportedSchemes[i];
  5187. }
  5188. return 0;
  5189. }
  5190. void HTTP2WinHttpTransportChannel::ContinueDrainChannel (
  5191. void
  5192. )
  5193. /*++
  5194. Routine Description:
  5195. Continue draining the channel after authentication challenge. We
  5196. need to drain the channel before we can proceed with the next
  5197. request. The number of bytes received is in NumberOfBytesTransferred.
  5198. If the channel was aborted in the meantime, issue receive
  5199. complete.
  5200. Arguments:
  5201. Return Value:
  5202. --*/
  5203. {
  5204. BYTE *Buffer;
  5205. RPC_STATUS RpcStatus;
  5206. BOOL HttpResult;
  5207. HANDLE LocalSyncEvent;
  5208. // read the reported bytes. Then query again. If the
  5209. // number of bytes reported is 0, issue a receive
  5210. // for RPC_P_AUTH_NEEDED
  5211. if (NumberOfBytesTransferred > 0)
  5212. {
  5213. ASSERT(State == whtcsDraining);
  5214. Buffer = (BYTE *)RpcAllocateBuffer(NumberOfBytesTransferred);
  5215. if (Buffer == NULL)
  5216. {
  5217. AsyncError = RPC_S_OUT_OF_MEMORY;
  5218. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5219. this
  5220. );
  5221. return;
  5222. }
  5223. // get into submissions context in order to safely access the
  5224. // request
  5225. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  5226. if (RpcStatus != RPC_S_OK)
  5227. {
  5228. RpcFreeBuffer(Buffer);
  5229. AsyncError = RpcStatus;
  5230. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5231. this
  5232. );
  5233. return;
  5234. }
  5235. ASSERT(SyncEvent == NULL);
  5236. LocalSyncEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  5237. if (LocalSyncEvent == NULL)
  5238. {
  5239. TopChannel->FinishSubmitAsync();
  5240. RpcFreeBuffer(Buffer);
  5241. AsyncError = RPC_S_OUT_OF_MEMORY;
  5242. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5243. this
  5244. );
  5245. return;
  5246. }
  5247. // read complete expects this state. Substitute it for draining
  5248. // for now. We'll restore it back later.
  5249. State = whtcsReceivedResponse;
  5250. SyncEvent = LocalSyncEvent;
  5251. HttpResult = WinHttpReadDataImp (hRequest,
  5252. Buffer,
  5253. NumberOfBytesTransferred,
  5254. NULL // Number of bytes read will be provided on async completion.
  5255. );
  5256. // read complete expects this state. Substitute it for draining
  5257. // for now. We'll restore it back later.
  5258. State = whtcsDraining;
  5259. SyncEvent = NULL;
  5260. CloseHandle(LocalSyncEvent);
  5261. // the data are here. This cannot fail
  5262. ASSERT(HttpResult);
  5263. RpcFreeBuffer(Buffer);
  5264. // ask for more
  5265. HttpResult = WinHttpQueryDataAvailableImp (hRequest,
  5266. NULL // Number of bytes available will be provided on async completion.
  5267. );
  5268. ASSERT(HttpResult);
  5269. TopChannel->FinishSubmitAsync();
  5270. // if WinHttp has the data, it will complete the QueryDataAvailable
  5271. // on the same thread as we are causing a recursive call to
  5272. // ContinueDrainChannel. If the recursion completed with success, we
  5273. // will already have RPC_P_AUTH_NEEDED for the AsyncError. Check
  5274. // for this case and bail out. All is done - we just need to get
  5275. // out of here
  5276. if (AsyncError == RPC_P_AUTH_NEEDED)
  5277. {
  5278. return;
  5279. }
  5280. else if (AsyncError == RPC_S_INTERNAL_ERROR)
  5281. {
  5282. // if WinHttpQueryDataAvailable resulted in recursive call
  5283. // of this function, deeper recursive levels may have set
  5284. // AsyncError to RPC_S_INTERNAL_ERROR. Reset if back
  5285. // once we pop out of the recursion. Since we will set it
  5286. // back on output from this function, this is a no-op.
  5287. AsyncError = RPC_S_OK;
  5288. }
  5289. VALIDATE (AsyncError)
  5290. {
  5291. RPC_P_RECEIVE_FAILED,
  5292. RPC_S_OK
  5293. } END_VALIDATE;
  5294. if (AsyncError != RPC_S_OK)
  5295. {
  5296. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5297. this
  5298. );
  5299. return;
  5300. }
  5301. AsyncError = RPC_S_INTERNAL_ERROR;
  5302. }
  5303. else
  5304. {
  5305. AsyncError = RPC_P_AUTH_NEEDED;
  5306. (void) COMMON_PostRuntimeEvent(HTTP2_WINHTTP_DIRECT_RECV,
  5307. this
  5308. );
  5309. }
  5310. }
  5311. /*********************************************************************
  5312. HTTP2ProxySocketTransportChannel
  5313. *********************************************************************/
  5314. RPC_STATUS HTTP2ProxySocketTransportChannel::AsyncCompleteHelper (
  5315. IN RPC_STATUS CurrentStatus
  5316. )
  5317. /*++
  5318. Routine Description:
  5319. Helper routine that helps complete an async operation
  5320. Arguments:
  5321. CurrentStatus - the current status of the operation
  5322. Return Value:
  5323. The status to return to the runtime.
  5324. --*/
  5325. {
  5326. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_COMPLETE_HELPER, HTTP2LOG_OT_PROXY_SOCKET_CHANNEL, CurrentStatus);
  5327. ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  5328. return RPC_P_PACKET_CONSUMED;
  5329. }
  5330. /*********************************************************************
  5331. HTTP2IISTransportChannel
  5332. *********************************************************************/
  5333. const char ServerErrorString[] = "HTTP/1.0 503 RPC Error: %X\r\n\r\n";
  5334. DWORD
  5335. ReplyToClientWithStatus (
  5336. IN EXTENSION_CONTROL_BLOCK *pECB,
  5337. IN RPC_STATUS RpcStatus
  5338. )
  5339. /*++
  5340. Routine Description:
  5341. Sends a reply to the client with the given error code as error.
  5342. Arguments:
  5343. pECB - extension control block
  5344. RpcStatus - error code to be returned to client
  5345. Return Value:
  5346. Return value appropriate for return to IIS (i.e. HSE_STATUS_*)
  5347. --*/
  5348. {
  5349. // size is the error string + 10 space for the error code
  5350. char Buffer[sizeof(ServerErrorString) + 10];
  5351. ULONG Size;
  5352. ULONG Status;
  5353. BOOL Result;
  5354. DWORD dwFlags = (HSE_IO_SYNC | HSE_IO_NODELAY);
  5355. sprintf (Buffer,
  5356. ServerErrorString,
  5357. RpcStatus
  5358. );
  5359. Size = RpcpStringLengthA(Buffer);
  5360. if (!pECB->WriteClient(pECB->ConnID, Buffer, &Size, dwFlags))
  5361. {
  5362. Status = GetLastError();
  5363. #ifdef DBG_ERROR
  5364. DbgPrint("ReplyToClientWithStatus(): failed: %d\n", Status);
  5365. #endif
  5366. return RPC_S_OUT_OF_MEMORY;
  5367. }
  5368. else
  5369. return RPC_S_OK;
  5370. }
  5371. RPC_STATUS HTTP2IISTransportChannel::Receive (
  5372. IN HTTP2TrafficType TrafficType
  5373. )
  5374. /*++
  5375. Routine Description:
  5376. Receive request
  5377. Arguments:
  5378. TrafficType - the type of traffic we want to receive
  5379. Return Value:
  5380. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5381. --*/
  5382. {
  5383. RPC_STATUS RpcStatus;
  5384. // if some data arrived with the ECB, pass them down for
  5385. // potential defragmentation
  5386. if (ECBDataConsumed == FALSE)
  5387. {
  5388. ECBDataConsumed = TRUE;
  5389. if (ControlBlock->cbAvailable > 0)
  5390. {
  5391. RpcStatus = DepositReceivedData (ControlBlock->cbAvailable,
  5392. ControlBlock->lpbData
  5393. );
  5394. if (RpcStatus != RPC_S_OK)
  5395. return RpcStatus;
  5396. }
  5397. // fall through to the actual receive
  5398. }
  5399. // ask the fragment receiver to perform a receive
  5400. return HTTP2FragmentReceiver::Receive (TrafficType);
  5401. }
  5402. RPC_STATUS HTTP2IISTransportChannel::ReceiveComplete (
  5403. IN RPC_STATUS EventStatus,
  5404. IN HTTP2TrafficType TrafficType,
  5405. IN BYTE *Buffer,
  5406. IN UINT BufferLength
  5407. )
  5408. /*++
  5409. Routine Description:
  5410. Receive complete notification.
  5411. Arguments:
  5412. EventStatus - status of the operation
  5413. TrafficType - the type of traffic we have received
  5414. Buffer - the received buffer (success only)
  5415. BufferLength - the length of the received buffer (success only)
  5416. Return Value:
  5417. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5418. --*/
  5419. {
  5420. // make sure nobody gets here. Everybody should be using the internal
  5421. // version
  5422. ASSERT(0);
  5423. return RPC_S_INTERNAL_ERROR;
  5424. }
  5425. void HTTP2IISTransportChannel::Abort (
  5426. IN RPC_STATUS RpcStatus
  5427. )
  5428. /*++
  5429. Routine Description:
  5430. Abort the channel
  5431. Arguments:
  5432. RpcStatus - the error code with which we abort
  5433. Return Value:
  5434. --*/
  5435. {
  5436. BOOL Result;
  5437. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_IIS_CHANNEL, RpcStatus);
  5438. ReplyToClientWithStatus(ControlBlock, RpcStatus);
  5439. // must abort the IIS session
  5440. Result = ControlBlock->ServerSupportFunction( ControlBlock->ConnID,
  5441. HSE_REQ_CLOSE_CONNECTION,
  5442. NULL,
  5443. NULL,
  5444. NULL);
  5445. if (Result == FALSE)
  5446. {
  5447. ASSERT(GetLastError() == WSAECONNRESET);
  5448. }
  5449. }
  5450. void HTTP2IISTransportChannel::FreeObject (
  5451. void
  5452. )
  5453. /*++
  5454. Routine Description:
  5455. Frees the object. Acts like a destructor for the
  5456. channel.
  5457. Arguments:
  5458. Return Value:
  5459. --*/
  5460. {
  5461. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5462. FreeIISControlBlock();
  5463. if (pReadBuffer)
  5464. {
  5465. RpcFreeBuffer(pReadBuffer);
  5466. pReadBuffer = NULL;
  5467. }
  5468. HTTP2IISTransportChannel::~HTTP2IISTransportChannel();
  5469. }
  5470. void HTTP2IISTransportChannel::IOCompleted (
  5471. IN ULONG Bytes,
  5472. DWORD Error
  5473. )
  5474. /*++
  5475. Routine Description:
  5476. An IO completed. Figure out what IO and what to do with it.
  5477. Arguments:
  5478. Return Value:
  5479. --*/
  5480. {
  5481. RPC_STATUS RpcStatus;
  5482. BYTE *Ignored;
  5483. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_IIS_IO_COMPLETED, HTTP2LOG_OT_IIS_CHANNEL, Error);
  5484. if (Direction == iistcdReceive)
  5485. {
  5486. (void) ReceiveCompleteInternal(Error ? RPC_P_RECEIVE_FAILED : RPC_S_OK,
  5487. http2ttRaw,
  5488. TRUE, // ReadCompleted
  5489. &Ignored,
  5490. (UINT *)&Bytes
  5491. );
  5492. }
  5493. else
  5494. {
  5495. if (Error == ERROR_SUCCESS)
  5496. {
  5497. ASSERT(Bytes == CurrentSendContext->maxWriteBuffer);
  5498. }
  5499. (void) SendComplete(Error ? RPC_P_SEND_FAILED : RPC_S_OK, CurrentSendContext);
  5500. }
  5501. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_IIS_IO_COMPLETED, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5502. }
  5503. void HTTP2IISTransportChannel::DirectReceive (
  5504. void
  5505. )
  5506. /*++
  5507. Routine Description:
  5508. Direct receive callback from the thread pool
  5509. Arguments:
  5510. Return Value:
  5511. --*/
  5512. {
  5513. ULONG Bytes;
  5514. RPC_STATUS RpcStatus;
  5515. BYTE *Ignored;
  5516. Bytes = iLastRead;
  5517. iLastRead = 0;
  5518. RpcStatus = ReceiveCompleteInternal(RPC_S_OK,
  5519. http2ttRaw,
  5520. FALSE, // ReadCompleted
  5521. &Ignored,
  5522. (UINT *)&Bytes
  5523. );
  5524. ASSERT(RpcStatus != RPC_S_INTERNAL_ERROR);
  5525. ASSERT(RpcStatus != RPC_P_PARTIAL_RECEIVE);
  5526. }
  5527. RPC_STATUS HTTP2IISTransportChannel::ReceiveCompleteInternal (
  5528. IN RPC_STATUS EventStatus,
  5529. IN HTTP2TrafficType TrafficType,
  5530. IN BOOL ReadCompleted,
  5531. IN OUT BYTE **Buffer,
  5532. IN OUT UINT *BufferLength
  5533. )
  5534. /*++
  5535. Routine Description:
  5536. Receive complete notification for the IIS transport channel. Somewhat
  5537. different signature than normal receive complete.
  5538. Arguments:
  5539. EventStatus - status of the operation
  5540. TrafficType - the type of traffic we have received
  5541. ReadCompleted - non-zero if a read completed. FALSE if it hasn't.
  5542. Buffer - the buffer. Must be NULL at this level on input. On
  5543. output contains the buffer for the current receive. If NULL
  5544. on output, we did not have a full packet. Undefined on failure.
  5545. BufferLength - the actual number of bytes received. On output the
  5546. number of bytes for the current packet. If 0 on output,
  5547. we did not have a complete packet. Undefined on failure.
  5548. Return Value:
  5549. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5550. --*/
  5551. {
  5552. if (ReadCompleted)
  5553. ReadsPending --;
  5554. ASSERT(ReadsPending == 0);
  5555. return HTTP2FragmentReceiver::ReceiveComplete (EventStatus,
  5556. TrafficType,
  5557. Buffer,
  5558. BufferLength
  5559. );
  5560. }
  5561. void HTTP2IISTransportChannel::FreeIISControlBlock (
  5562. void
  5563. )
  5564. /*++
  5565. Routine Description:
  5566. Frees the IIS control block associated with this channel
  5567. Arguments:
  5568. Return Value:
  5569. --*/
  5570. {
  5571. BOOL Result;
  5572. if (IISCloseEnabled)
  5573. {
  5574. Result = ControlBlock->ServerSupportFunction( ControlBlock->ConnID,
  5575. HSE_REQ_DONE_WITH_SESSION,
  5576. NULL,
  5577. NULL,
  5578. NULL);
  5579. ASSERT(Result);
  5580. }
  5581. ControlBlock = NULL;
  5582. }
  5583. RPC_STATUS HTTP2IISTransportChannel::AsyncCompleteHelper (
  5584. IN RPC_STATUS CurrentStatus
  5585. )
  5586. /*++
  5587. Routine Description:
  5588. A helper function that completes an async io.
  5589. Arguments:
  5590. CurrentStatus - the status with which the complete
  5591. notification completed.
  5592. Return Value:
  5593. --*/
  5594. {
  5595. return ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  5596. }
  5597. RPC_STATUS HTTP2IISTransportChannel::PostReceive (
  5598. void
  5599. )
  5600. /*++
  5601. Routine Description:
  5602. Posts a receive to IIS.
  5603. Arguments:
  5604. Return Value:
  5605. RPC_S_OK or RPC_S_* error
  5606. Note: May be called from both submission and upcall context
  5607. --*/
  5608. {
  5609. BOOL Result;
  5610. RPC_STATUS RpcStatus;
  5611. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, 0);
  5612. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  5613. if (RpcStatus != RPC_S_OK)
  5614. return RpcStatus;
  5615. ASSERT (Direction == iistcdReceive);
  5616. if (pReadBuffer == NULL)
  5617. {
  5618. pReadBuffer = (BYTE *)RpcAllocateBuffer(iPostSize);
  5619. if (pReadBuffer == NULL)
  5620. {
  5621. TopChannel->FinishSubmitAsync();
  5622. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, RPC_S_OUT_OF_MEMORY);
  5623. return RPC_S_OUT_OF_MEMORY;
  5624. }
  5625. MaxReadBuffer = iPostSize;
  5626. }
  5627. else
  5628. {
  5629. ASSERT(iLastRead < MaxReadBuffer);
  5630. }
  5631. ReadsPending ++;
  5632. ASSERT(ReadsPending == 1);
  5633. BytesToTransfer = MaxReadBuffer - iLastRead;
  5634. Result = ControlBlock->ServerSupportFunction(ControlBlock->ConnID,
  5635. HSE_REQ_ASYNC_READ_CLIENT,
  5636. pReadBuffer + iLastRead,
  5637. &BytesToTransfer,
  5638. &IISIoFlags
  5639. );
  5640. TopChannel->FinishSubmitAsync();
  5641. if (Result == FALSE)
  5642. {
  5643. ReadsPending --;
  5644. ASSERT(ReadsPending == 0);
  5645. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5646. RpcStatus = RPC_P_RECEIVE_FAILED;
  5647. }
  5648. else
  5649. RpcStatus = RPC_S_OK;
  5650. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_IIS_CHANNEL, RpcStatus);
  5651. return RpcStatus;
  5652. }
  5653. ULONG HTTP2IISTransportChannel::GetPostRuntimeEvent (
  5654. void
  5655. )
  5656. /*++
  5657. Routine Description:
  5658. Gets the message to be posted to the runtime.
  5659. Arguments:
  5660. Return Value:
  5661. The message to post to the runtime
  5662. --*/
  5663. {
  5664. return IN_PROXY_IIS_DIRECT_RECV;
  5665. }
  5666. /*********************************************************************
  5667. HTTP2IISSenderTransportChannel
  5668. *********************************************************************/
  5669. RPC_STATUS HTTP2IISSenderTransportChannel::Send (
  5670. IN OUT HTTP2SendContext *SendContext
  5671. )
  5672. /*++
  5673. Routine Description:
  5674. Send request
  5675. Arguments:
  5676. SendContext - the send context
  5677. Return Value:
  5678. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5679. --*/
  5680. {
  5681. BOOL Result;
  5682. ULONG LocalSendsPending;
  5683. RPC_STATUS RpcStatus;
  5684. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, (ULONG_PTR)SendContext);
  5685. Mutex.Request();
  5686. LocalSendsPending = SendsPending.Increment();
  5687. if ((LocalSendsPending > 1) || ReadsPending)
  5688. {
  5689. // queue and exit
  5690. SendContext->SetListEntryUsed();
  5691. RpcpInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  5692. Mutex.Clear();
  5693. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, 1);
  5694. return RPC_S_OK;
  5695. }
  5696. Mutex.Clear();
  5697. if (Direction == iistcdReceive)
  5698. ReverseDirection();
  5699. CurrentSendContext = SendContext;
  5700. BytesToTransfer = SendContext->maxWriteBuffer;
  5701. Result = ControlBlock->WriteClient(ControlBlock->ConnID,
  5702. SendContext->pWriteBuffer,
  5703. &BytesToTransfer,
  5704. IISIoFlags
  5705. );
  5706. if (Result == FALSE)
  5707. {
  5708. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5709. RpcStatus = RPC_P_SEND_FAILED;
  5710. }
  5711. else
  5712. RpcStatus = RPC_S_OK;
  5713. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_IIS_SENDER_CHANNEL, RpcStatus);
  5714. return RpcStatus;
  5715. }
  5716. RPC_STATUS HTTP2IISSenderTransportChannel::SendComplete (
  5717. IN RPC_STATUS EventStatus,
  5718. IN OUT HTTP2SendContext *SendContext
  5719. )
  5720. /*++
  5721. Routine Description:
  5722. Send complete notification
  5723. Arguments:
  5724. EventStatus - status of the operation
  5725. SendContext - the send context
  5726. Return Value:
  5727. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5728. --*/
  5729. {
  5730. ULONG LocalSendsPending;
  5731. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_IIS_SENDER_CHANNEL, EventStatus);
  5732. CurrentSendContext = NULL;
  5733. // decrement this in advance so that if we post another send on send
  5734. // complete, it doesn't get queued
  5735. LocalSendsPending = SendsPending.Decrement();
  5736. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  5737. if ((EventStatus == RPC_S_OK)
  5738. || (EventStatus == RPC_P_PACKET_CONSUMED) )
  5739. {
  5740. EventStatus = SendQueuedContextIfNecessary (LocalSendsPending, EventStatus);
  5741. }
  5742. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_IIS_SENDER_CHANNEL, EventStatus);
  5743. return AsyncCompleteHelper(EventStatus);
  5744. }
  5745. void HTTP2IISSenderTransportChannel::Abort (
  5746. IN RPC_STATUS RpcStatus
  5747. )
  5748. /*++
  5749. Routine Description:
  5750. Abort the channel
  5751. Arguments:
  5752. RpcStatus - the error code with which we abort
  5753. Return Value:
  5754. --*/
  5755. {
  5756. HTTP2SendContext *QueuedSendContext;
  5757. LIST_ENTRY *QueuedListEntry;
  5758. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_IIS_SENDER_CHANNEL, RpcStatus);
  5759. HTTP2IISTransportChannel::Abort(RpcStatus);
  5760. Mutex.Request();
  5761. if (SendsPending.GetInteger() > 1)
  5762. {
  5763. ASSERT(!RpcpIsListEmpty(&BufferQueueHead));
  5764. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  5765. do
  5766. {
  5767. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  5768. SendsPending.Decrement();
  5769. HTTP2TransportChannel::SendComplete(RpcStatus, QueuedSendContext);
  5770. TopChannel->RemoveReference();
  5771. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  5772. }
  5773. while (QueuedListEntry != &BufferQueueHead);
  5774. }
  5775. Mutex.Clear();
  5776. }
  5777. void HTTP2IISSenderTransportChannel::FreeObject (
  5778. void
  5779. )
  5780. /*++
  5781. Routine Description:
  5782. Frees the object. Acts like a destructor for the
  5783. channel.
  5784. Arguments:
  5785. Return Value:
  5786. --*/
  5787. {
  5788. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_FREE_OBJECT, HTTP2LOG_OT_IIS_SENDER_CHANNEL, 0);
  5789. FreeIISControlBlock();
  5790. HTTP2IISSenderTransportChannel::~HTTP2IISSenderTransportChannel();
  5791. }
  5792. RPC_STATUS HTTP2IISSenderTransportChannel::ReceiveCompleteInternal (
  5793. IN RPC_STATUS EventStatus,
  5794. IN HTTP2TrafficType TrafficType,
  5795. IN BOOL ReadCompleted,
  5796. IN OUT BYTE **Buffer,
  5797. IN OUT UINT *BufferLength
  5798. )
  5799. /*++
  5800. Routine Description:
  5801. Receive complete notification for the IIS sender transport channel. Somewhat
  5802. different signature than normal receive complete.
  5803. Arguments:
  5804. EventStatus - status of the operation
  5805. TrafficType - the type of traffic we have received
  5806. ReadCompleted - non-zero if a read completed. FALSE if it hasn't.
  5807. Buffer - the buffer. Must be NULL at this level on input. On
  5808. output contains the buffer for the current receive. If NULL
  5809. on output, we did not have a full packet. Undefined on failure.
  5810. BufferLength - the actual number of bytes received. On output the
  5811. number of bytes for the current packet. If 0 on output,
  5812. we did not have a complete packet. Undefined on failure.
  5813. Return Value:
  5814. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5815. --*/
  5816. {
  5817. RPC_STATUS RpcStatus;
  5818. ULONG LocalSendsPending;
  5819. Mutex.Request();
  5820. // decrease the reads pending and check the sends within the mutex -
  5821. // this ensures atomicity with respect to the send path's (which is
  5822. // the only path we race with) increase of the sends and check of the
  5823. // reads
  5824. if (ReadCompleted)
  5825. ReadsPending --;
  5826. ASSERT(ReadsPending == 0);
  5827. LocalSendsPending = SendsPending.GetInteger();
  5828. Mutex.Clear();
  5829. RpcStatus = HTTP2FragmentReceiver::ReceiveComplete (EventStatus,
  5830. TrafficType,
  5831. Buffer,
  5832. BufferLength
  5833. );
  5834. if ((RpcStatus == RPC_P_PACKET_CONSUMED)
  5835. ||
  5836. (
  5837. (RpcStatus == RPC_S_OK)
  5838. &&
  5839. (*Buffer != NULL)
  5840. )
  5841. )
  5842. {
  5843. RpcStatus = SendQueuedContextIfNecessary (LocalSendsPending, RpcStatus);
  5844. }
  5845. return RpcStatus;
  5846. }
  5847. RPC_STATUS HTTP2IISSenderTransportChannel::SendQueuedContextIfNecessary (
  5848. IN ULONG LocalSendsPending,
  5849. IN RPC_STATUS EventStatus
  5850. )
  5851. /*++
  5852. Routine Description:
  5853. Checks if any send contexts are queued for sending, and if yes, sends
  5854. the first one (which on completion will send the next, etc).
  5855. Arguments:
  5856. LocalSendsPending - the number of sends pending at the time the current
  5857. operation completed save for the count of the current operation (if it
  5858. was send)
  5859. EventStatus - the RPC Status so far. Must be a success error status
  5860. (RPC_S_OK or RPC_P_PACKET_CONSUMED)
  5861. Return Value:
  5862. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  5863. --*/
  5864. {
  5865. HTTP2SendContext *QueuedSendContext;
  5866. LIST_ENTRY *QueuedListEntry;
  5867. BOOL Result;
  5868. if (LocalSendsPending != 0)
  5869. {
  5870. Mutex.Request();
  5871. if (Direction == iistcdReceive)
  5872. ReverseDirection();
  5873. QueuedListEntry = RpcpRemoveHeadList(&BufferQueueHead);
  5874. // it is possible that if an abort executed between getting LocalSendsPending
  5875. // in caller and grabbing the mutex here that the list is empty.
  5876. ASSERT(QueuedListEntry);
  5877. if (QueuedListEntry == &BufferQueueHead)
  5878. {
  5879. Mutex.Clear();
  5880. return EventStatus;
  5881. }
  5882. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  5883. Mutex.Clear();
  5884. QueuedSendContext->SetListEntryUnused();
  5885. // need to synchronize with aborts (rule 9)
  5886. EventStatus = TopChannel->BeginSimpleSubmitAsync();
  5887. if (EventStatus == RPC_S_OK)
  5888. {
  5889. CurrentSendContext = QueuedSendContext;
  5890. BytesToTransfer = QueuedSendContext->maxWriteBuffer;
  5891. Result = ControlBlock->WriteClient(ControlBlock->ConnID,
  5892. QueuedSendContext->pWriteBuffer,
  5893. &BytesToTransfer,
  5894. IISIoFlags
  5895. );
  5896. if (Result == FALSE)
  5897. {
  5898. EventStatus = RPC_P_SEND_FAILED;
  5899. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  5900. // the send failed. We don't get a notification for it
  5901. // so we must issue one. Reference for the send we
  5902. // failed to post is already added
  5903. EventStatus = HTTP2TransportChannel::SendComplete(EventStatus, QueuedSendContext);
  5904. TopChannel->RemoveReference();
  5905. }
  5906. else
  5907. {
  5908. // must already be ok
  5909. ASSERT(EventStatus == RPC_S_OK);
  5910. }
  5911. TopChannel->FinishSubmitAsync();
  5912. }
  5913. }
  5914. return EventStatus;
  5915. }
  5916. /*********************************************************************
  5917. HTTP2GenericReceiver
  5918. *********************************************************************/
  5919. void HTTP2GenericReceiver::FreeObject (
  5920. void
  5921. )
  5922. /*++
  5923. Routine Description:
  5924. Frees the object. Acts like a destructor for the
  5925. channel.
  5926. Arguments:
  5927. Return Value:
  5928. --*/
  5929. {
  5930. if (LowerLayer)
  5931. LowerLayer->FreeObject();
  5932. HTTP2GenericReceiver::~HTTP2GenericReceiver();
  5933. }
  5934. void HTTP2GenericReceiver::TransferStateToNewReceiver (
  5935. OUT HTTP2GenericReceiver *NewReceiver
  5936. )
  5937. /*++
  5938. Routine Description:
  5939. Transfers all the settings from this receiver (i.e. the state
  5940. of the receive) to a new one.
  5941. Arguments:
  5942. NewReceiver - the new receiver to transfer the settings to
  5943. Return Value:
  5944. Notes:
  5945. This must be called in an upcall context (i.e. no real receives
  5946. pending) and the channel on which this is called must be non-default
  5947. by now.
  5948. --*/
  5949. {
  5950. NewReceiver->ReceiveWindow = ReceiveWindow;
  5951. }
  5952. RPC_STATUS HTTP2GenericReceiver::BytesReceivedNotification (
  5953. IN ULONG Bytes
  5954. )
  5955. /*++
  5956. Routine Description:
  5957. Notifies channel that bytes have been received.
  5958. Arguments:
  5959. Bytes - the number of data bytes received.
  5960. Return Value:
  5961. RPC_S_OK if the received bytes did not violate the
  5962. flow control protocol. RPC_S_PROTOCOL error otherwise.
  5963. --*/
  5964. {
  5965. Mutex.VerifyOwned();
  5966. BytesReceived += Bytes;
  5967. BytesInWindow += Bytes;
  5968. ASSERT(BytesInWindow <= ReceiveWindow);
  5969. FreeWindowAdvertised -= Bytes;
  5970. if (FreeWindowAdvertised < 0)
  5971. {
  5972. ASSERT(0);
  5973. // sender sent data even though
  5974. // we told it we don't have enough window
  5975. // to receive it - protocol violation
  5976. return RPC_S_PROTOCOL_ERROR;
  5977. }
  5978. return RPC_S_OK;
  5979. }
  5980. void HTTP2GenericReceiver::BytesConsumedNotification (
  5981. IN ULONG Bytes,
  5982. IN BOOL OwnsMutex,
  5983. OUT BOOL *IssueAck,
  5984. OUT ULONG *BytesReceivedForAck,
  5985. OUT ULONG *WindowForAck
  5986. )
  5987. /*++
  5988. Routine Description:
  5989. Notifies channel that bytes have been consumed and can
  5990. be freed from the receive window of the channel.
  5991. Arguments:
  5992. Bytes - the number of data bytes consumed.
  5993. OwnsMutex - non-zero if the mutex for the channel is
  5994. already owned.
  5995. IssueAck - must be FALSE on input. If the caller needs
  5996. to issue an Ack, it will be set to non-zero on
  5997. output.
  5998. BytesReceivedForAck - on output, if IssueAck is non-zero,
  5999. it will contain the bytes received to put in the
  6000. ack packet. If IssueAck is FALSE, it is undefined.
  6001. WindowForAck - on output, if IssueAck is non-zero,
  6002. it will contain the window available to put in the
  6003. ack packet. If IssueAck is FALSE, it is undefined.
  6004. Return Value:
  6005. --*/
  6006. {
  6007. ULONG ReceiveWindowThreshold;
  6008. if (OwnsMutex)
  6009. {
  6010. Mutex.VerifyOwned();
  6011. }
  6012. else
  6013. {
  6014. Mutex.Request();
  6015. }
  6016. ASSERT(*IssueAck == FALSE);
  6017. BytesInWindow -= Bytes;
  6018. // make sure we don't wrap
  6019. ASSERT(BytesInWindow <= ReceiveWindow);
  6020. ReceiveWindowThreshold = ReceiveWindow >> 1;
  6021. if (FreeWindowAdvertised < (LONG)ReceiveWindowThreshold)
  6022. {
  6023. // we fell below the threshold. ACK our current window
  6024. *IssueAck = TRUE;
  6025. FreeWindowAdvertised = ReceiveWindow - BytesInWindow;
  6026. ASSERT(FreeWindowAdvertised >= 0);
  6027. *BytesReceivedForAck = BytesReceived;
  6028. *WindowForAck = FreeWindowAdvertised;
  6029. }
  6030. if (OwnsMutex == FALSE)
  6031. {
  6032. Mutex.Clear();
  6033. }
  6034. }
  6035. RPC_STATUS HTTP2GenericReceiver::SendFlowControlAck (
  6036. IN ULONG BytesReceivedForAck,
  6037. IN ULONG WindowForAck
  6038. )
  6039. /*++
  6040. Routine Description:
  6041. Sends a flow control Ack packet.
  6042. Arguments:
  6043. BytesReceivedForAck - the number of bytes received while
  6044. we were issuing the Ack
  6045. WindowForAck - the window available when BytesReceivedForAck
  6046. bytes have been received
  6047. Return Value:
  6048. RPC_S_OK or RPC_S_* for error
  6049. Notes:
  6050. This must be called in a neutral context.
  6051. --*/
  6052. {
  6053. return TopChannel->ForwardFlowControlAck (BytesReceivedForAck,
  6054. WindowForAck
  6055. );
  6056. }
  6057. /*********************************************************************
  6058. HTTP2EndpointReceiver
  6059. *********************************************************************/
  6060. RPC_STATUS HTTP2EndpointReceiver::Receive (
  6061. IN HTTP2TrafficType TrafficType
  6062. )
  6063. /*++
  6064. Routine Description:
  6065. Receive request
  6066. Arguments:
  6067. TrafficType - the type of traffic we want to receive
  6068. Return Value:
  6069. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6070. --*/
  6071. {
  6072. BOOL PostReceive;
  6073. RPC_STATUS RpcStatus;
  6074. BOOL DequeuePacket;
  6075. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, TrafficType);
  6076. DequeuePacket = FALSE;
  6077. PostReceive = FALSE;
  6078. Mutex.Request();
  6079. switch (TrafficType)
  6080. {
  6081. case http2ttNone:
  6082. ASSERT(0);
  6083. RpcStatus = RPC_S_INTERNAL_ERROR;
  6084. Mutex.Clear();
  6085. return RpcStatus;
  6086. case http2ttRTS:
  6087. // we cannot issue two RTS receives.
  6088. ASSERT((ReceivesPosted & http2ttRTS) == 0);
  6089. // if we have RTS receives queued, dequeue one and
  6090. // complete it
  6091. if (ReceivesQueued == http2ttRTS)
  6092. {
  6093. ASSERT(DirectCompletePosted == FALSE);
  6094. DirectCompletePosted = TRUE;
  6095. DequeuePacket = TRUE;
  6096. }
  6097. else
  6098. {
  6099. // we have no packets queued, or only data packets
  6100. // queued. If we have no data request pending, create
  6101. // a request pending. Otherwise just add ourselves to
  6102. // the map
  6103. if (ReceivesPosted)
  6104. {
  6105. ASSERT(ReceivesPosted == http2ttData);
  6106. ReceivesPosted = http2ttAny;
  6107. }
  6108. else
  6109. {
  6110. PostReceive = TRUE;
  6111. ReceivesPosted = http2ttRTS;
  6112. }
  6113. }
  6114. break;
  6115. case http2ttData:
  6116. // we cannot issue two Data receives.
  6117. ASSERT((ReceivesPosted & http2ttData) == 0);
  6118. // if we have Data receives queued, dequeue one and
  6119. // complete it
  6120. if (ReceivesQueued == http2ttData)
  6121. {
  6122. ASSERT(DirectCompletePosted == FALSE);
  6123. DirectCompletePosted = TRUE;
  6124. DequeuePacket = TRUE;
  6125. }
  6126. else
  6127. {
  6128. // we have no packets queued, or only RTS packets
  6129. // queued. If we have no RTS request pending, create
  6130. // a request pending. Otherwise just add ourselves to
  6131. // the map
  6132. if (ReceivesPosted)
  6133. {
  6134. ASSERT(ReceivesPosted == http2ttRTS);
  6135. ReceivesPosted = http2ttAny;
  6136. }
  6137. else
  6138. {
  6139. PostReceive = TRUE;
  6140. ReceivesPosted = http2ttData;
  6141. }
  6142. }
  6143. break;
  6144. default:
  6145. ASSERT(0);
  6146. RpcStatus = RPC_S_INTERNAL_ERROR;
  6147. Mutex.Clear();
  6148. return RpcStatus;
  6149. }
  6150. // only one of PostReceive and DequeuePacket can be set here.
  6151. // Neither is ok too.
  6152. ASSERT((PostReceive ^ DequeuePacket)
  6153. || ((PostReceive == FALSE)
  6154. &&
  6155. (DequeuePacket == FALSE)
  6156. )
  6157. );
  6158. Mutex.Clear();
  6159. if (DequeuePacket)
  6160. {
  6161. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 0);
  6162. (void) COMMON_PostRuntimeEvent(HTTP2_DIRECT_RECEIVE,
  6163. this
  6164. );
  6165. return RPC_S_OK;
  6166. }
  6167. if (PostReceive == FALSE)
  6168. {
  6169. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 1);
  6170. return RPC_S_OK;
  6171. }
  6172. RpcStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  6173. if (RpcStatus != RPC_S_OK)
  6174. {
  6175. // we have indicated our receive as pending, yet we
  6176. // couldn't submit it. Not good. Must attempt to
  6177. // remove it from the pending variable unless somebody
  6178. // else already did (which is possible if we wanted
  6179. // to submit data and there was already pending RTS).
  6180. Mutex.Request();
  6181. switch (ReceivesPosted)
  6182. {
  6183. case http2ttNone:
  6184. // should not be possible
  6185. ASSERT(FALSE);
  6186. RpcStatus = RPC_S_INTERNAL_ERROR;
  6187. Mutex.Clear();
  6188. return RpcStatus;
  6189. case http2ttData:
  6190. if (TrafficType == http2ttData)
  6191. ReceivesPosted = http2ttNone;
  6192. else
  6193. {
  6194. // not possible that we submitted RTS
  6195. // and have data pending but not RTS
  6196. ASSERT(0);
  6197. Mutex.Clear();
  6198. return RPC_S_INTERNAL_ERROR;
  6199. }
  6200. break;
  6201. case http2ttRTS:
  6202. if (TrafficType == http2ttRTS)
  6203. ReceivesPosted = http2ttNone;
  6204. else
  6205. {
  6206. // possible that we attempted to submit data,
  6207. // but while we were trying, an async RTS submission
  6208. // failed, and we indicated it asynchronously. In this
  6209. // case we must not indicate the failure synchronously
  6210. RpcStatus = RPC_S_OK;
  6211. }
  6212. break;
  6213. case http2ttAny:
  6214. if (TrafficType == http2ttRTS)
  6215. ReceivesPosted = http2ttData;
  6216. else
  6217. ReceivesPosted = http2ttRTS;
  6218. break;
  6219. default:
  6220. ASSERT(0);
  6221. Mutex.Clear();
  6222. return RPC_S_INTERNAL_ERROR;
  6223. }
  6224. Mutex.Clear();
  6225. }
  6226. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV, HTTP2LOG_OT_ENDPOINT_RECEIVER, 3);
  6227. return RpcStatus;
  6228. }
  6229. RPC_STATUS HTTP2EndpointReceiver::ReceiveComplete (
  6230. IN RPC_STATUS EventStatus,
  6231. IN HTTP2TrafficType TrafficType,
  6232. IN BYTE *Buffer,
  6233. IN UINT BufferLength
  6234. )
  6235. /*++
  6236. Routine Description:
  6237. Receive complete notification.
  6238. Arguments:
  6239. EventStatus - status of the operation
  6240. TrafficType - the type of traffic we have received
  6241. Buffer - the received buffer (success only)
  6242. BufferLength - the length of the received buffer (success only)
  6243. Return Value:
  6244. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6245. --*/
  6246. {
  6247. HTTP2TrafficType NewReceivesPosted;
  6248. HTTP2TrafficType ThisCompleteTrafficType;
  6249. RPC_STATUS RpcStatus;
  6250. RPC_STATUS RpcStatus2;
  6251. BOOL BufferQueued;
  6252. RPC_STATUS RTSStatus;
  6253. RPC_STATUS DataStatus;
  6254. BOOL ReceiveCompletesFailed;
  6255. BYTE *CurrentPosition;
  6256. USHORT PacketFlags;
  6257. BOOL IssueAck;
  6258. ULONG BytesReceivedForAck;
  6259. ULONG WindowForAck;
  6260. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, EventStatus);
  6261. BufferQueued = FALSE;
  6262. Mutex.Request();
  6263. if (EventStatus == RPC_S_OK)
  6264. {
  6265. if (IsRTSPacket(Buffer))
  6266. ThisCompleteTrafficType = http2ttRTS;
  6267. else
  6268. {
  6269. ThisCompleteTrafficType = http2ttData;
  6270. EventStatus = BytesReceivedNotification(BufferLength
  6271. );
  6272. if (EventStatus != RPC_S_OK)
  6273. {
  6274. // fall through with an error. Don't free the buffer
  6275. // (Rule 34).
  6276. }
  6277. }
  6278. }
  6279. if (EventStatus != RPC_S_OK)
  6280. {
  6281. if (ReceivesPosted == http2ttAny)
  6282. ThisCompleteTrafficType = http2ttData;
  6283. else
  6284. ThisCompleteTrafficType = ReceivesPosted;
  6285. }
  6286. ReceiveCompletesFailed = FALSE;
  6287. switch (ThisCompleteTrafficType)
  6288. {
  6289. case http2ttData:
  6290. if ((ReceivesPosted & http2ttData) == FALSE)
  6291. {
  6292. // we haven't asked for data, but we get some. We'll
  6293. // have to queue it
  6294. ASSERT(ReceivesQueued != http2ttRTS);
  6295. ReceivesQueued = http2ttData;
  6296. if (BufferQueue.PutOnQueue(Buffer, BufferLength))
  6297. {
  6298. ReceiveCompletesFailed = TRUE;
  6299. RpcFreeBuffer(Buffer);
  6300. }
  6301. BufferQueued = TRUE;
  6302. }
  6303. else
  6304. {
  6305. ReceivesPosted = (HTTP2TrafficType)(ReceivesPosted ^ http2ttData);
  6306. NewReceivesPosted = ReceivesPosted;
  6307. }
  6308. break;
  6309. case http2ttRTS:
  6310. if ((ReceivesPosted & http2ttRTS) == FALSE)
  6311. {
  6312. // we haven't asked for RTS, but we get some. We'll
  6313. // have to queue it
  6314. ASSERT(ReceivesQueued != http2ttData);
  6315. ReceivesQueued = http2ttRTS;
  6316. if (BufferQueue.PutOnQueue(Buffer, BufferLength))
  6317. {
  6318. ReceiveCompletesFailed = TRUE;
  6319. RpcFreeBuffer(Buffer);
  6320. }
  6321. BufferQueued = TRUE;
  6322. }
  6323. else
  6324. {
  6325. ReceivesPosted = (HTTP2TrafficType)(ReceivesPosted ^ http2ttRTS);
  6326. NewReceivesPosted = ReceivesPosted;
  6327. }
  6328. break;
  6329. default:
  6330. ASSERT(0);
  6331. break;
  6332. }
  6333. IssueAck = FALSE;
  6334. if ((BufferQueued == FALSE)
  6335. && (ReceiveCompletesFailed == FALSE)
  6336. && (ThisCompleteTrafficType == http2ttData)
  6337. && (EventStatus == RPC_S_OK))
  6338. {
  6339. // we know the data will be consumed immediately
  6340. BytesConsumedNotification (BufferLength,
  6341. TRUE, // OwnsMutex
  6342. &IssueAck,
  6343. &BytesReceivedForAck,
  6344. &WindowForAck
  6345. );
  6346. }
  6347. Mutex.Clear();
  6348. if (IssueAck)
  6349. {
  6350. RpcStatus = SendFlowControlAck (BytesReceivedForAck,
  6351. WindowForAck
  6352. );
  6353. if (RpcStatus != RPC_S_OK)
  6354. {
  6355. // turn this into a failure
  6356. EventStatus = RpcStatus;
  6357. // fall through to issuing the notification
  6358. if (EventStatus == RPC_P_SEND_FAILED)
  6359. EventStatus = RPC_P_RECEIVE_FAILED;
  6360. }
  6361. }
  6362. if (ReceiveCompletesFailed)
  6363. {
  6364. // we got an unwanted receive, and couldn't queue it.
  6365. // Abort the connection
  6366. TopChannel->AbortConnection(RPC_S_OUT_OF_MEMORY);
  6367. return RPC_P_PACKET_CONSUMED;
  6368. }
  6369. if (BufferQueued)
  6370. {
  6371. ASSERT(ReceivesPosted != http2ttNone);
  6372. // the packet was not of the type we wanted.
  6373. // Submit another receive hoping to get what we want
  6374. RpcStatus = TopChannel->BeginSubmitAsync();
  6375. if (RpcStatus == RPC_S_OK)
  6376. {
  6377. // we know we have one type of receive in the map. Nobody
  6378. // can post another. Just post ours
  6379. RpcStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  6380. TopChannel->FinishSubmitAsync();
  6381. if (RpcStatus != RPC_S_OK)
  6382. {
  6383. TopChannel->RemoveReference();
  6384. }
  6385. }
  6386. if (RpcStatus != RPC_S_OK)
  6387. {
  6388. // we failed to submit the receive. We have to issue notification for it
  6389. RpcStatus = HTTP2TransportChannel::ReceiveComplete(RpcStatus,
  6390. ReceivesPosted,
  6391. NULL, // Buffer
  6392. 0 // BufferLength
  6393. );
  6394. TopChannel->AbortConnection(RpcStatus);
  6395. }
  6396. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RPC_P_PACKET_CONSUMED);
  6397. // if we have queued, this means the runtime did not
  6398. // ask for this packet. Don't let it see it.
  6399. return RPC_P_PACKET_CONSUMED;
  6400. }
  6401. // The buffer was not queued - pass it up
  6402. RpcStatus = HTTP2TransportChannel::ReceiveComplete(EventStatus,
  6403. ThisCompleteTrafficType,
  6404. Buffer,
  6405. BufferLength
  6406. );
  6407. if (NewReceivesPosted != http2ttNone)
  6408. {
  6409. // if we left something in the map, nobody could have
  6410. // posted a raw receive - they would have just upgraded the
  6411. // map. It could still have been aborted though
  6412. ASSERT((NewReceivesPosted == http2ttRTS)
  6413. ||
  6414. (NewReceivesPosted == http2ttData));
  6415. // see what was left as pending recieve, and
  6416. // actually submit that. We do that only if we didn't
  6417. // fail before. If we did, don't bother
  6418. if (EventStatus == RPC_S_OK)
  6419. {
  6420. RpcStatus2 = TopChannel->BeginSimpleSubmitAsync();
  6421. if (RpcStatus2 == RPC_S_OK)
  6422. {
  6423. RpcStatus2 = HTTP2TransportChannel::Receive(http2ttRaw);
  6424. TopChannel->FinishSubmitAsync();
  6425. }
  6426. }
  6427. else
  6428. {
  6429. // transfer the error code
  6430. RpcStatus2 = EventStatus;
  6431. }
  6432. if (RpcStatus2 != RPC_S_OK)
  6433. {
  6434. // we failed to submit the receive. We have to issue notification for it
  6435. RpcStatus2 = HTTP2TransportChannel::ReceiveComplete(RpcStatus2,
  6436. NewReceivesPosted,
  6437. NULL, // Buffer
  6438. 0 // BufferLength
  6439. );
  6440. if (NewReceivesPosted == http2ttRTS)
  6441. {
  6442. ASSERT(RpcStatus2 != RPC_S_OK);
  6443. }
  6444. TopChannel->RemoveReference(); // remove reference for the receive complete
  6445. }
  6446. }
  6447. // here, ThisCompleteTrafficType is the type of completed receive and
  6448. // RpcStatus is the status for it. NewReceivesPosted is the next submit we received
  6449. // (http2ttNone if none) and RpcStatus2 is the status for it.
  6450. // make sure nobody has left unconsumed success RTS packets
  6451. if (ThisCompleteTrafficType == http2ttRTS)
  6452. {
  6453. ASSERT(RpcStatus != RPC_S_OK);
  6454. }
  6455. // if there is only one receive type, no merging is necessary - just return
  6456. if (NewReceivesPosted == http2ttNone)
  6457. {
  6458. // consume RTS receives
  6459. if (ThisCompleteTrafficType == http2ttRTS)
  6460. RpcStatus = RPC_P_PACKET_CONSUMED;
  6461. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6462. return RpcStatus;
  6463. }
  6464. // Process them and determine the appropriate return code. If we
  6465. // have two receives, we merge them as per the table below
  6466. // N First Receive Second Receive Return value Note
  6467. // -- -------------- ----------------- ------------- ---------
  6468. // 1 DS RS S
  6469. // 2 DS RC S
  6470. // 3 DS RF S Abort
  6471. // 4 DF RS F
  6472. // 5 DF RC F
  6473. // 6 DF RF F Choose first receive error
  6474. // 7 RS DS Invalid combination (first RTS should have been consumed)
  6475. // 8 RC DS C
  6476. // 9 RF DS S Abort
  6477. // 10 RS DF Invalid combination (first RTS should have been consumed)
  6478. // 11 RC DF C Abort
  6479. // 12 RF DF F Choose first receive error
  6480. if (ThisCompleteTrafficType == http2ttData)
  6481. {
  6482. ASSERT(NewReceivesPosted == http2ttRTS);
  6483. DataStatus = RpcStatus;
  6484. RTSStatus = RpcStatus2;
  6485. }
  6486. else
  6487. {
  6488. ASSERT(NewReceivesPosted == http2ttData);
  6489. DataStatus = RpcStatus2;
  6490. RTSStatus = RpcStatus;
  6491. }
  6492. if (DataStatus == RPC_S_OK)
  6493. {
  6494. if (RTSStatus == RPC_S_OK)
  6495. {
  6496. // case 1 - just return ok
  6497. RpcStatus = RTSStatus;
  6498. }
  6499. else if (RTSStatus == RPC_P_PACKET_CONSUMED)
  6500. {
  6501. // case 2
  6502. if (ThisCompleteTrafficType == http2ttData)
  6503. {
  6504. RpcStatus = DataStatus;
  6505. }
  6506. else
  6507. {
  6508. // case 8
  6509. RpcStatus = RTSStatus;
  6510. }
  6511. }
  6512. else
  6513. {
  6514. // cases 3 & 9
  6515. TopChannel->AbortConnection(RTSStatus);
  6516. }
  6517. }
  6518. else
  6519. {
  6520. if (RTSStatus == RPC_S_OK)
  6521. {
  6522. // case 4
  6523. RpcStatus = DataStatus;
  6524. }
  6525. else if (RTSStatus == RPC_P_PACKET_CONSUMED)
  6526. {
  6527. // case 5
  6528. if (ThisCompleteTrafficType == http2ttData)
  6529. {
  6530. RpcStatus = DataStatus;
  6531. }
  6532. else
  6533. {
  6534. // case 11
  6535. TopChannel->AbortConnection(DataStatus);
  6536. RpcStatus = RTSStatus;
  6537. }
  6538. }
  6539. else
  6540. {
  6541. // cases 6 & 12
  6542. // nothing to do. First error is already in RpcStatus
  6543. }
  6544. }
  6545. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  6546. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  6547. || (RpcStatus == RPC_P_SEND_FAILED)
  6548. || (RpcStatus == RPC_S_OUT_OF_MEMORY))
  6549. RpcStatus = RPC_P_RECEIVE_FAILED;
  6550. VALIDATE (RpcStatus)
  6551. {
  6552. RPC_S_OK,
  6553. RPC_P_PACKET_CONSUMED,
  6554. RPC_P_RECEIVE_FAILED
  6555. } END_VALIDATE;
  6556. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6557. return RpcStatus;
  6558. }
  6559. void HTTP2EndpointReceiver::Abort (
  6560. IN RPC_STATUS RpcStatus
  6561. )
  6562. /*++
  6563. Routine Description:
  6564. Abort the channel
  6565. Arguments:
  6566. RpcStatus - the error code with which we abort
  6567. Return Value:
  6568. --*/
  6569. {
  6570. BYTE *CurrentBuffer;
  6571. UINT Ignored;
  6572. ULONG SizeOfQueueToLeave;
  6573. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_ENDPOINT_RECEIVER, RpcStatus);
  6574. HTTP2TransportChannel::Abort(RpcStatus);
  6575. Mutex.Request();
  6576. // if there is a direct complete posted, we have to
  6577. // leave one element in the queue, because the
  6578. // direct complete routine will need it
  6579. if (DirectCompletePosted)
  6580. SizeOfQueueToLeave = 1;
  6581. else
  6582. SizeOfQueueToLeave = 0;
  6583. while (BufferQueue.Size() > SizeOfQueueToLeave)
  6584. {
  6585. CurrentBuffer = (BYTE *) BufferQueue.TakeOffEndOfQueue(&Ignored);
  6586. // the elements in the queue are unwanted anyway -
  6587. // they don't have refcounts or anything else - just
  6588. // free them
  6589. RpcFreeBuffer(CurrentBuffer);
  6590. }
  6591. // If we have taken elements off the queue,
  6592. // mark that there are no longer any receives queued on this channel.
  6593. if (SizeOfQueueToLeave == 0)
  6594. {
  6595. ReceivesQueued = http2ttNone;
  6596. }
  6597. Mutex.Clear();
  6598. }
  6599. void HTTP2EndpointReceiver::FreeObject (
  6600. void
  6601. )
  6602. /*++
  6603. Routine Description:
  6604. Frees the object. Acts like a destructor for the
  6605. channel.
  6606. Arguments:
  6607. Return Value:
  6608. --*/
  6609. {
  6610. if (LowerLayer)
  6611. LowerLayer->FreeObject();
  6612. HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  6613. }
  6614. RPC_STATUS HTTP2EndpointReceiver::DirectReceiveComplete (
  6615. OUT BYTE **ReceivedBuffer,
  6616. OUT ULONG *ReceivedBufferLength,
  6617. OUT void **RuntimeConnection,
  6618. OUT BOOL *IsServer
  6619. )
  6620. /*++
  6621. Routine Description:
  6622. Direct receive completion (i.e. we posted a receive
  6623. to ourselves). We can be called in only one case -
  6624. a receive was submitted and there were already
  6625. queued receives.
  6626. Arguments:
  6627. ReceivedBuffer - the buffer that we received.
  6628. ReceivedBufferLength - the length of the received
  6629. buffer
  6630. RuntimeConnection - the connection to return to the runtime
  6631. if the packet is not consumed.
  6632. IsServer - non-zero if the server
  6633. Return Value:
  6634. RPC_S_OK, RPC_P_PACKET_CONSUMED or RPC_S_* errors.
  6635. Notes:
  6636. The directly posted receive carries a reference count
  6637. --*/
  6638. {
  6639. BYTE *Buffer;
  6640. ULONG BufferLength;
  6641. RPC_STATUS RpcStatus;
  6642. HTTP2TrafficType QueuedPacketsType;
  6643. BOOL IssueAck;
  6644. ULONG BytesReceivedForAck;
  6645. ULONG WindowForAck;
  6646. BOOL PacketNeedsFlowControl;
  6647. *IsServer = this->IsServer;
  6648. *RuntimeConnection = TopChannel->GetRuntimeConnection();
  6649. // dequeue a packet
  6650. // we cannot have a queue and a posted receive at the same time
  6651. ASSERT((ReceivesPosted & ReceivesQueued) == FALSE);
  6652. Mutex.Request();
  6653. ASSERT(DirectCompletePosted);
  6654. ASSERT(DirectReceiveInProgress == FALSE);
  6655. // they must be set in this order, because if a thread in
  6656. // TransferStateToNewReceiver synchronizes with us, it will check
  6657. // them in reverse order.
  6658. InterlockedIncrement((long *)&DirectReceiveInProgress);
  6659. DirectCompletePosted = FALSE;
  6660. QueuedPacketsType = ReceivesQueued;
  6661. Buffer = (BYTE *)BufferQueue.TakeOffQueue((UINT *)&BufferLength);
  6662. // even if aborted, at least one buffer must have been left for us
  6663. // because we had the DirectCompletePosted flag set
  6664. ASSERT (Buffer);
  6665. if (BufferQueue.IsQueueEmpty())
  6666. ReceivesQueued = http2ttNone;
  6667. PacketNeedsFlowControl = (((ULONG_PTR)Buffer & 1) == 0);
  6668. Buffer = (BYTE *)(((ULONG_PTR)Buffer) & (~(ULONG_PTR)1));
  6669. RpcStatus = RPC_S_OK;
  6670. *ReceivedBuffer = Buffer;
  6671. *ReceivedBufferLength = BufferLength;
  6672. // we know the data will be consumed.
  6673. IssueAck = FALSE;
  6674. if ((QueuedPacketsType == http2ttData) && PacketNeedsFlowControl)
  6675. {
  6676. BytesConsumedNotification (BufferLength,
  6677. TRUE, // OwnsMutex
  6678. &IssueAck,
  6679. &BytesReceivedForAck,
  6680. &WindowForAck
  6681. );
  6682. }
  6683. Mutex.Clear();
  6684. if (IssueAck)
  6685. {
  6686. RpcStatus = SendFlowControlAck (BytesReceivedForAck,
  6687. WindowForAck
  6688. );
  6689. if (RpcStatus != RPC_S_OK)
  6690. {
  6691. // turn this into a failure. Note that we must supply a buffer
  6692. // on failure, hence we don't free it (Rule 34)
  6693. // fall through to issuing the notification
  6694. }
  6695. }
  6696. // decrement if before receive complete. In receive complete
  6697. // we may post another receive and cause a race
  6698. InterlockedDecrement((long *)&DirectReceiveInProgress);
  6699. // one of three things must happen here if this is a client. Either this
  6700. // is RTS packet, or somebody sync waits for this packet, or the connection
  6701. // is not exclusive
  6702. if (!this->IsServer)
  6703. {
  6704. // actually do the checks
  6705. if ((QueuedPacketsType != http2ttRTS)
  6706. && (((HTTP2ClientChannel *)UpperLayer)->IsSyncRecvPending() == FALSE)
  6707. && (I_RpcTransIsClientConnectionExclusive(*RuntimeConnection))
  6708. )
  6709. {
  6710. ASSERT(0);
  6711. // make it hold on free builds
  6712. *((ULONG *)0) = RpcStatus;
  6713. }
  6714. }
  6715. RpcStatus = HTTP2TransportChannel::ReceiveComplete(RpcStatus,
  6716. QueuedPacketsType,
  6717. Buffer,
  6718. BufferLength
  6719. );
  6720. if (QueuedPacketsType == http2ttRTS)
  6721. {
  6722. ASSERT(RpcStatus != RPC_S_OK);
  6723. RpcStatus = RPC_P_PACKET_CONSUMED;
  6724. }
  6725. else
  6726. {
  6727. if (RpcStatus == RPC_P_SEND_FAILED)
  6728. RpcStatus = RPC_P_RECEIVE_FAILED;
  6729. }
  6730. RpcStatus = AsyncCompleteHelper(RpcStatus);
  6731. VALIDATE(RpcStatus)
  6732. {
  6733. RPC_P_CONNECTION_CLOSED,
  6734. RPC_P_RECEIVE_FAILED,
  6735. RPC_P_CONNECTION_SHUTDOWN,
  6736. RPC_P_PACKET_CONSUMED,
  6737. RPC_S_OK
  6738. } END_VALIDATE;
  6739. return RpcStatus;
  6740. }
  6741. RPC_STATUS HTTP2EndpointReceiver::TransferStateToNewReceiver (
  6742. OUT HTTP2EndpointReceiver *NewReceiver
  6743. )
  6744. /*++
  6745. Routine Description:
  6746. Transfers all the settings from this receiver (i.e. the state
  6747. of the receive) to a new one.
  6748. Arguments:
  6749. NewReceiver - the new receiver to transfer the settings to
  6750. Return Value:
  6751. RPC_S_OK or RPC_S_* errors.
  6752. Notes:
  6753. This must be called in an upcall context (i.e. no real receives
  6754. pending) and the channel on which this is called must be non-default
  6755. by now.
  6756. --*/
  6757. {
  6758. void *Buffer;
  6759. UINT BufferLength;
  6760. void *QueueElement;
  6761. int Result;
  6762. BOOL QueueTransferred;
  6763. // this channel is not a default channel by now. We know that
  6764. // there may be receives in progress, but no new receives will be
  6765. // submitted.
  6766. while (TRUE)
  6767. {
  6768. Mutex.Request();
  6769. if (DirectCompletePosted || DirectReceiveInProgress)
  6770. {
  6771. Mutex.Clear();
  6772. Sleep(5);
  6773. }
  6774. else
  6775. break;
  6776. }
  6777. NewReceiver->Mutex.Request();
  6778. // transfer the settings for the base class
  6779. HTTP2GenericReceiver::TransferStateToNewReceiver(NewReceiver);
  6780. if (NewReceiver->BufferQueue.IsQueueEmpty() == FALSE)
  6781. {
  6782. // the only way we can end up here is if the channel replacement
  6783. // took so long that the peer started pinging us. This is a protocol
  6784. // error.
  6785. NewReceiver->Mutex.Clear();
  6786. Mutex.Clear();
  6787. return RPC_S_PROTOCOL_ERROR;
  6788. }
  6789. QueueTransferred = FALSE;
  6790. while (TRUE)
  6791. {
  6792. QueueElement = BufferQueue.TakeOffEndOfQueue(&BufferLength);
  6793. if (QueueElement == 0)
  6794. {
  6795. QueueTransferred = TRUE;
  6796. break;
  6797. }
  6798. if (NewReceiver->BufferQueue.PutOnFrontOfQueue((void *)((ULONG_PTR)QueueElement | 1), BufferLength) != 0)
  6799. {
  6800. // guaranteed to succeed since we never decrease buffers
  6801. BufferQueue.PutOnFrontOfQueue(QueueElement, BufferLength);
  6802. break;
  6803. }
  6804. }
  6805. if (QueueTransferred == FALSE)
  6806. {
  6807. // failure - out of memory. Since the buffers are unwanted
  6808. // we can just return failure. Both channels will be
  6809. // aborted
  6810. NewReceiver->Mutex.Clear();
  6811. Mutex.Clear();
  6812. return RPC_S_OUT_OF_MEMORY;
  6813. }
  6814. NewReceiver->ReceivesQueued = ReceivesQueued;
  6815. // Mark that there are no longer any receives queued on this channel.
  6816. ReceivesQueued = http2ttNone;
  6817. // we never transfer data receives. They will be transferred by our caller
  6818. // We also preserve existing receives on the new receiver. There is a race where
  6819. // data receives may have ended up on the new channel. That's ok as long as they
  6820. // are off the old.
  6821. ASSERT(((NewReceiver->ReceivesPosted & http2ttData) == 0)
  6822. || ((ReceivesPosted & http2ttData) == 0));
  6823. NewReceiver->ReceivesPosted
  6824. = (HTTP2TrafficType)(NewReceiver->ReceivesPosted | (ReceivesPosted & (~http2ttData)));
  6825. // direct complete posted cannot be true here
  6826. ASSERT(DirectCompletePosted == FALSE);
  6827. NewReceiver->Mutex.Clear();
  6828. Mutex.Clear();
  6829. return RPC_S_OK;
  6830. }
  6831. /*********************************************************************
  6832. HTTP2ProxyReceiver
  6833. *********************************************************************/
  6834. RPC_STATUS HTTP2ProxyReceiver::ReceiveComplete (
  6835. IN RPC_STATUS EventStatus,
  6836. IN HTTP2TrafficType TrafficType,
  6837. IN BYTE *Buffer,
  6838. IN UINT BufferLength
  6839. )
  6840. /*++
  6841. Routine Description:
  6842. Receive complete notification.
  6843. Arguments:
  6844. EventStatus - status of the operation
  6845. TrafficType - the type of traffic we have received
  6846. Buffer - the received buffer (success only)
  6847. BufferLength - the length of the received buffer (success only)
  6848. Return Value:
  6849. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6850. --*/
  6851. {
  6852. if ((EventStatus == RPC_S_OK) && (IsRTSPacket(Buffer) == FALSE))
  6853. {
  6854. Mutex.Request();
  6855. EventStatus = BytesReceivedNotification(BufferLength
  6856. );
  6857. Mutex.Clear();
  6858. if (EventStatus != RPC_S_OK)
  6859. {
  6860. // consume the packet and fall through with an error
  6861. RpcFreeBuffer(Buffer);
  6862. }
  6863. }
  6864. return HTTP2TransportChannel::ReceiveComplete(EventStatus,
  6865. TrafficType,
  6866. Buffer,
  6867. BufferLength
  6868. );
  6869. }
  6870. void HTTP2ProxyReceiver::Abort (
  6871. IN RPC_STATUS RpcStatus
  6872. )
  6873. /*++
  6874. Routine Description:
  6875. Abort the channel.
  6876. Arguments:
  6877. RpcStatus - the error code with which we abort
  6878. Return Value:
  6879. --*/
  6880. {
  6881. BYTE *CurrentBuffer;
  6882. UINT Ignored;
  6883. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PROXY_RECEIVER, RpcStatus);
  6884. HTTP2TransportChannel::Abort(RpcStatus);
  6885. Mutex.Request();
  6886. while (BufferQueue.Size() > 0)
  6887. {
  6888. CurrentBuffer = (BYTE *) BufferQueue.TakeOffQueue(&Ignored);
  6889. // the elements in the queue are unwanted anyway -
  6890. // they don't have refcounts or anything else - just
  6891. // free them
  6892. RpcFreeBuffer(CurrentBuffer);
  6893. }
  6894. Mutex.Clear();
  6895. }
  6896. void HTTP2ProxyReceiver::FreeObject (
  6897. void
  6898. )
  6899. /*++
  6900. Routine Description:
  6901. Frees the object. Acts like a destructor for the
  6902. channel.
  6903. Arguments:
  6904. Return Value:
  6905. --*/
  6906. {
  6907. if (LowerLayer)
  6908. LowerLayer->FreeObject();
  6909. HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  6910. }
  6911. /*********************************************************************
  6912. HTTP2PlugChannel
  6913. *********************************************************************/
  6914. C_ASSERT(http2plRTSPlugged == http2ttRTS);
  6915. C_ASSERT(http2plDataPlugged == http2ttData);
  6916. RPC_STATUS HTTP2PlugChannel::Send (
  6917. IN OUT HTTP2SendContext *SendContext
  6918. )
  6919. /*++
  6920. Routine Description:
  6921. Send request
  6922. Arguments:
  6923. SendContext - the send context
  6924. Return Value:
  6925. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  6926. --*/
  6927. {
  6928. HTTP2TrafficType SendType;
  6929. RPC_STATUS RpcStatus;
  6930. #if DBG
  6931. TrafficSentOnChannel = TRUE;
  6932. #endif // DBG
  6933. SendType = SendContext->TrafficType;
  6934. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_PLUG_CHANNEL, PtrToUlong(SendContext));
  6935. ASSERT((SendType == http2ttData)
  6936. || (SendType == http2ttRTS)
  6937. || (SendType == http2ttRaw) );
  6938. // if the plug level says this packet should not go through, queue it
  6939. // This means the traffic is no raw, and the plug level is less than
  6940. // the send type. Since the constants are ordered this comparison is
  6941. // sufficient
  6942. if ((SendType != http2ttRaw) && (PlugLevel <= SendType))
  6943. {
  6944. SendContext->SetListEntryUsed();
  6945. Mutex.Request();
  6946. // queue and exit
  6947. if (SendContext->Flags & SendContextFlagPutInFront)
  6948. {
  6949. RpcpfInsertHeadList(&BufferQueueHead, &SendContext->ListEntry);
  6950. }
  6951. else
  6952. {
  6953. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  6954. }
  6955. Mutex.Clear();
  6956. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_PLUG_CHANNEL, 0);
  6957. return RPC_S_OK;
  6958. }
  6959. else
  6960. {
  6961. // can't put in front on unplugged channel
  6962. ASSERT((SendContext->Flags & SendContextFlagPutInFront) == 0);
  6963. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  6964. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_PLUG_CHANNEL, RpcStatus);
  6965. return RpcStatus;
  6966. }
  6967. }
  6968. void HTTP2PlugChannel::Abort (
  6969. IN RPC_STATUS RpcStatus
  6970. )
  6971. /*++
  6972. Routine Description:
  6973. Abort the channel
  6974. Arguments:
  6975. RpcStatus - the error code with which we abort
  6976. Return Value:
  6977. Note: All sends carry a refcount. We must fully complete the sends
  6978. --*/
  6979. {
  6980. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PLUG_CHANNEL, RpcStatus);
  6981. HTTP2TransportChannel::Abort(RpcStatus);
  6982. SendFailedStatus = RpcStatus;
  6983. // Abort is made from submission context. We
  6984. // know it is synchronized with other submissions
  6985. // and we cannot issue upcalls for it. We will just post
  6986. // as many direct send completions as there are buffers in
  6987. // the queue. When the post comes around, it will dequeue
  6988. // and free one buffer for every post.
  6989. // We know that after abort there will be no more submissions,
  6990. // so not dequeuing them is fine
  6991. if (!RpcpIsListEmpty(&BufferQueueHead))
  6992. {
  6993. (void) COMMON_PostRuntimeEvent(PLUG_CHANNEL_DIRECT_SEND,
  6994. this
  6995. );
  6996. }
  6997. }
  6998. void HTTP2PlugChannel::FreeObject (
  6999. void
  7000. )
  7001. /*++
  7002. Routine Description:
  7003. Frees the object. Acts like a destructor for the
  7004. channel.
  7005. Arguments:
  7006. Return Value:
  7007. --*/
  7008. {
  7009. if (LowerLayer)
  7010. LowerLayer->FreeObject();
  7011. HTTP2PlugChannel::~HTTP2PlugChannel();
  7012. }
  7013. void HTTP2PlugChannel::Reset (
  7014. void
  7015. )
  7016. /*++
  7017. Routine Description:
  7018. Reset the channel for next open/send/receive. This is
  7019. used in submission context only and implies there are no
  7020. pending operations on the channel. It is used on the client
  7021. during opening the connection to do quick negotiation on the
  7022. same connection instead of opening a new connection every time.
  7023. Arguments:
  7024. Return Value:
  7025. --*/
  7026. {
  7027. ASSERT(SendFailedStatus);
  7028. ASSERT(RpcpIsListEmpty(&BufferQueueHead));
  7029. PlugLevel = http2plDataPlugged;
  7030. LowerLayer->Reset();
  7031. }
  7032. RPC_STATUS HTTP2PlugChannel::DirectSendComplete (
  7033. void
  7034. )
  7035. /*++
  7036. Routine Description:
  7037. Direct send complete notification. Complete the send
  7038. passing it only through channels that have seen it (i.e.
  7039. above us)
  7040. Arguments:
  7041. Return Value:
  7042. RPC_S_OK
  7043. --*/
  7044. {
  7045. HTTP2SendContext *QueuedSendContext;
  7046. LIST_ENTRY *QueuedListEntry;
  7047. RPC_STATUS RpcStatus;
  7048. BOOL IsListEmpty;
  7049. ASSERT(SendFailedStatus != RPC_S_INTERNAL_ERROR);
  7050. // we wouldn't have a post if there wasn't something
  7051. // in the list.
  7052. ASSERT(!RpcpIsListEmpty(&BufferQueueHead));
  7053. do
  7054. {
  7055. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  7056. // capture the state of the list before we do AsyncCompleteHelper.
  7057. // after that, the this object may be gone.
  7058. IsListEmpty = RpcpIsListEmpty(&BufferQueueHead);
  7059. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  7060. RpcStatus = HTTP2TransportChannel::SendComplete(SendFailedStatus, QueuedSendContext);
  7061. // we don't care about the return code.
  7062. (void) AsyncCompleteHelper(RpcStatus);
  7063. // if the list is empty by now, the this object is gone. Don't touch anything
  7064. }
  7065. while (!IsListEmpty);
  7066. return RPC_S_OK;
  7067. }
  7068. RPC_STATUS HTTP2PlugChannel::Unplug (
  7069. void
  7070. )
  7071. /*++
  7072. Routine Description:
  7073. Unplugs the channel. This means that all bottled up traffic
  7074. starts flowing forward.
  7075. Arguments:
  7076. Return Value:
  7077. RPC_S_OK or RPC_S_* errors
  7078. --*/
  7079. {
  7080. HTTP2SendContext *QueuedSendContext;
  7081. LIST_ENTRY *QueuedListEntry;
  7082. RPC_STATUS RpcStatus;
  7083. // first, send pending traffic. Then open the channel. Otherwise
  7084. // traffic may get out of order
  7085. while (TRUE)
  7086. {
  7087. Mutex.Request();
  7088. QueuedListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  7089. // if we had non-zero elements ...
  7090. if (QueuedListEntry != &BufferQueueHead)
  7091. {
  7092. Mutex.Clear();
  7093. }
  7094. else
  7095. {
  7096. // we have zero elements - just unplug the channel
  7097. PlugLevel = http2plUnplugged;
  7098. Mutex.Clear();
  7099. RpcStatus = RPC_S_OK;
  7100. break;
  7101. }
  7102. QueuedSendContext = CONTAINING_RECORD(QueuedListEntry, HTTP2SendContext, ListEntry);
  7103. QueuedSendContext->SetListEntryUnused();
  7104. // get into submission context - rule 9.
  7105. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  7106. if (RpcStatus == RPC_S_OK)
  7107. {
  7108. RpcStatus = HTTP2TransportChannel::Send(QueuedSendContext);
  7109. TopChannel->FinishSubmitAsync();
  7110. }
  7111. if (RpcStatus != RPC_S_OK)
  7112. {
  7113. QueuedSendContext->SetListEntryUsed();
  7114. Mutex.Request();
  7115. RpcpfInsertHeadList(&BufferQueueHead, QueuedListEntry);
  7116. Mutex.Clear();
  7117. break;
  7118. }
  7119. }
  7120. return RpcStatus;
  7121. }
  7122. void HTTP2PlugChannel::SetStrongPlug (
  7123. void
  7124. )
  7125. /*++
  7126. Routine Description:
  7127. Upgrades the default plug level (http2plDataPlugged) to
  7128. RTS (http2plRTSPlugged)
  7129. Arguments:
  7130. Return Value:
  7131. --*/
  7132. {
  7133. // make sure we haven't done any sending on the channel. The
  7134. // channel cannot change plug levels after the first send
  7135. ASSERT(TrafficSentOnChannel == FALSE);
  7136. PlugLevel = http2plRTSPlugged;
  7137. }
  7138. /*********************************************************************
  7139. HTTP2ProxyPlugChannel
  7140. *********************************************************************/
  7141. RPC_STATUS HTTP2ProxyPlugChannel::AsyncCompleteHelper (
  7142. IN RPC_STATUS CurrentStatus
  7143. )
  7144. /*++
  7145. Routine Description:
  7146. A helper function that completes an async io.
  7147. Arguments:
  7148. CurrentStatus - the status with which the complete
  7149. notification completed.
  7150. Return Value:
  7151. --*/
  7152. {
  7153. return ProxyAsyncCompleteHelper(TopChannel, CurrentStatus);
  7154. }
  7155. /*********************************************************************
  7156. HTTP2FlowControlSender
  7157. *********************************************************************/
  7158. RPC_STATUS HTTP2FlowControlSender::Send (
  7159. IN OUT HTTP2SendContext *SendContext
  7160. )
  7161. /*++
  7162. Routine Description:
  7163. Send request
  7164. Arguments:
  7165. SendContext - the send context
  7166. Return Value:
  7167. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7168. if SendContextFlagSendLast is set, the following semantics applies:
  7169. RPC_S_OK - no sends are pending. Last context directly sent
  7170. ERROR_IO_PENDING - sends were pending. When they are all drained
  7171. top channel and virtual connection will be notified through
  7172. the LastPacketSentNotification mechanism
  7173. RPC_S_* errors occured during synchronous send
  7174. --*/
  7175. {
  7176. RPC_STATUS RpcStatus;
  7177. HTTP2SendContext *LocalSendContext;
  7178. if (SendContext->TrafficType == http2ttData)
  7179. {
  7180. // we can't send data without knowing the receive window
  7181. // of the peer
  7182. ASSERT(PeerReceiveWindow != 0);
  7183. }
  7184. if (SendContext->Flags & SendContextFlagSendLast)
  7185. {
  7186. // register the last send. We know if this is called, no
  7187. // new sends will be submitted. However, we race with the
  7188. // send complete thread
  7189. InterlockedExchangePointer((PVOID *)&SendContextOnDrain, SendContext);
  7190. if (SendsPending.GetInteger() == 0)
  7191. {
  7192. // no sends are pending. Attempt to grab back the context
  7193. // and do it synchronously
  7194. LocalSendContext =
  7195. (HTTP2SendContext *)InterlockedExchangePointer((PVOID *)&SendContextOnDrain, NULL);
  7196. if (LocalSendContext)
  7197. {
  7198. // we managed to grab it back. We have won the right to
  7199. // synchronously submit the last context.
  7200. RpcStatus = HTTP2TransportChannel::Send(LocalSendContext);
  7201. // return ok or an error
  7202. return RpcStatus;
  7203. }
  7204. }
  7205. // either there are sends pending, or we lost the race and we have to
  7206. // rely on asynchronous notifications
  7207. return ERROR_IO_PENDING;
  7208. }
  7209. SendsPending.Increment();
  7210. return SendInternal(SendContext,
  7211. FALSE // IgnoreQueuedPackets
  7212. );
  7213. }
  7214. RPC_STATUS HTTP2FlowControlSender::SendComplete (
  7215. IN RPC_STATUS EventStatus,
  7216. IN OUT HTTP2SendContext *SendContext
  7217. )
  7218. /*++
  7219. Routine Description:
  7220. Send complete notification
  7221. Arguments:
  7222. EventStatus - the status of the send
  7223. SendContext - send context
  7224. Return Value:
  7225. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7226. --*/
  7227. {
  7228. RPC_STATUS RpcStatus;
  7229. RPC_STATUS RpcStatus2;
  7230. int LocalSendsPending;
  7231. HTTP2SendContext *LocalSendContextOnDrain;
  7232. LocalSendsPending = SendsPending.Decrement();
  7233. // in the case of Last packet to send completing, the counter will wrap to -1 here because
  7234. // the last send is not present in SendsPending. That's ok.
  7235. RpcStatus = HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  7236. if (LocalSendsPending == 0)
  7237. {
  7238. LocalSendContextOnDrain = (HTTP2SendContext *) SendContextOnDrain;
  7239. if (LocalSendContextOnDrain)
  7240. {
  7241. // try to consume the SendContextOnDrain in a thread safe manner
  7242. // in respect to a thread that is setting it. In the cases where SendContextOnDrain
  7243. // will be called the channel is already detached, so we know no new sends will
  7244. // be submitted and we don't need to worry about the race with SendsPending going
  7245. // up again
  7246. LocalSendContextOnDrain =
  7247. (HTTP2SendContext *)InterlockedCompareExchangePointer((PVOID *)&SendContextOnDrain,
  7248. NULL,
  7249. LocalSendContextOnDrain
  7250. );
  7251. if (LocalSendContextOnDrain)
  7252. {
  7253. // remove the reference for the previous send
  7254. TopChannel->RemoveReference();
  7255. // last packet must be RTS.
  7256. ASSERT(LocalSendContextOnDrain->TrafficType == http2ttRTS);
  7257. RpcStatus = TopChannel->LastPacketSentNotification(LocalSendContextOnDrain);
  7258. // don't care about return code. This channel is dying anyway
  7259. RpcStatus2 = TopChannel->Send(LocalSendContextOnDrain);
  7260. // the second error takes precedence here
  7261. if (RpcStatus2 != RPC_S_OK)
  7262. RpcStatus = RpcStatus2;
  7263. }
  7264. }
  7265. }
  7266. return RpcStatus;
  7267. }
  7268. void HTTP2FlowControlSender::Abort (
  7269. IN RPC_STATUS RpcStatus
  7270. )
  7271. /*++
  7272. Routine Description:
  7273. Abort the channel
  7274. Arguments:
  7275. RpcStatus - the error code with which we abort
  7276. Return Value:
  7277. --*/
  7278. {
  7279. // we have a bunch of sends carrying ref-counts, etc.
  7280. // We must make sure they are completed.
  7281. HTTP2TransportChannel::Abort(RpcStatus);
  7282. // we know we are synchronized with everybody else
  7283. if (!RpcpIsListEmpty(&BufferQueueHead))
  7284. {
  7285. AbortStatus = RpcStatus;
  7286. (void) COMMON_PostRuntimeEvent(HTTP2_FLOW_CONTROL_DIRECT_SEND,
  7287. this
  7288. );
  7289. }
  7290. }
  7291. void HTTP2FlowControlSender::FreeObject (
  7292. void
  7293. )
  7294. /*++
  7295. Routine Description:
  7296. Frees the object. Acts like a destructor for the
  7297. channel.
  7298. Arguments:
  7299. Return Value:
  7300. --*/
  7301. {
  7302. if (LowerLayer)
  7303. LowerLayer->FreeObject();
  7304. HTTP2FlowControlSender::~HTTP2FlowControlSender();
  7305. }
  7306. void HTTP2FlowControlSender::SendCancelled (
  7307. IN HTTP2SendContext *SendContext
  7308. )
  7309. /*++
  7310. Routine Description:
  7311. A lower channel cancelled a send already passed through this channel.
  7312. Arguments:
  7313. SendContext - the send context of the send that was cancelled
  7314. Return Value:
  7315. Note:
  7316. The channel must not be receiving new requests by now (i.e.
  7317. it must be non-default and fully drained)
  7318. --*/
  7319. {
  7320. SendsPending.Decrement();
  7321. UpperLayer->SendCancelled(SendContext);
  7322. }
  7323. RPC_STATUS HTTP2FlowControlSender::FlowControlAckNotify (
  7324. IN ULONG BytesReceivedForAck,
  7325. IN ULONG WindowForAck
  7326. )
  7327. /*++
  7328. Routine Description:
  7329. Notifies the channel that a flow control ack has arrived.
  7330. Arguments:
  7331. BytesReceivedForAck - the bytes received from the ack packet
  7332. WindowForAck - the available window advertised in the ack
  7333. Return Value:
  7334. RPC_S_OK or RPC_S_PROTOCOL_ERROR if the received values are bogus
  7335. --*/
  7336. {
  7337. LIST_ENTRY *CurrentListEntry;
  7338. LIST_ENTRY *NextListEntry;
  7339. HTTP2SendContext *SendContext;
  7340. RPC_STATUS RpcStatus;
  7341. BOOL ChannelNeedsRecycling;
  7342. #if 0
  7343. DbgPrint("%X: HTTP2FlowControlSender::FlowControlAckNotify: %d; %d; %d\n",
  7344. GetCurrentProcessId(),
  7345. DataBytesSent,
  7346. BytesReceivedForAck,
  7347. WindowForAck
  7348. );
  7349. #endif
  7350. RpcStatus = RPC_S_OK;
  7351. ChannelNeedsRecycling = FALSE;
  7352. Mutex.Request();
  7353. CORRUPTION_ASSERT((DataBytesSent - BytesReceivedForAck) <= PeerReceiveWindow);
  7354. if ((DataBytesSent - BytesReceivedForAck) > PeerReceiveWindow)
  7355. {
  7356. Mutex.Clear();
  7357. return RPC_S_PROTOCOL_ERROR;
  7358. }
  7359. PeerAvailableWindow = WindowForAck - (DataBytesSent - BytesReceivedForAck);
  7360. CORRUPTION_ASSERT(PeerAvailableWindow <= PeerReceiveWindow);
  7361. if (PeerAvailableWindow > PeerReceiveWindow)
  7362. {
  7363. Mutex.Clear();
  7364. return RPC_S_PROTOCOL_ERROR;
  7365. }
  7366. // did we free up enough window to send some of our queued buffers?
  7367. CurrentListEntry = BufferQueueHead.Flink;
  7368. while (CurrentListEntry != &BufferQueueHead)
  7369. {
  7370. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7371. if (SendContext->maxWriteBuffer <= PeerAvailableWindow)
  7372. {
  7373. SendContext->SetListEntryUnused();
  7374. RpcpfRemoveHeadList(&BufferQueueHead);
  7375. // set the CurrentListEntry for the next iteration of the loop
  7376. CurrentListEntry = BufferQueueHead.Flink;
  7377. // send it through this channel. This will update DataBytesSent
  7378. // and PeerAvailableWindow
  7379. RpcStatus = SendInternal(SendContext,
  7380. TRUE // IgnoreQueuedPackets
  7381. );
  7382. if (RpcStatus != RPC_S_OK)
  7383. {
  7384. if (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING)
  7385. {
  7386. // we failed to send - stick back the current context and
  7387. // return error. This will cause caller to abort and
  7388. // this will complete all queued sends
  7389. SendContext->SetListEntryUsed();
  7390. RpcpfInsertHeadList(&BufferQueueHead, &SendContext->ListEntry);
  7391. break;
  7392. }
  7393. else
  7394. {
  7395. // remeber that we need to return RPC_P_CHANNEL_NEEDS_RECYCLING at
  7396. // the end
  7397. ChannelNeedsRecycling = TRUE;
  7398. }
  7399. }
  7400. }
  7401. else
  7402. {
  7403. // we don't have enough space to send more. Break out of the loop
  7404. break;
  7405. }
  7406. }
  7407. Mutex.Clear();
  7408. if (ChannelNeedsRecycling)
  7409. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  7410. else
  7411. return RpcStatus;
  7412. }
  7413. void HTTP2FlowControlSender::GetBufferQueue (
  7414. OUT LIST_ENTRY *NewQueueHead
  7415. )
  7416. /*++
  7417. Routine Description:
  7418. Grab all queued buffers and pile them on the list head
  7419. that we passed to it. All refcounts must be removed (i.e.
  7420. undone).
  7421. Arguments:
  7422. NewQueueHead - new queue heads to pile buffers on
  7423. Return Value:
  7424. --*/
  7425. {
  7426. LIST_ENTRY *CurrentListEntry;
  7427. LIST_ENTRY *NextListEntry;
  7428. HTTP2SendContext *SendContext;
  7429. ASSERT(RpcpIsListEmpty(NewQueueHead));
  7430. Mutex.Request();
  7431. CurrentListEntry = BufferQueueHead.Flink;
  7432. while (CurrentListEntry != &BufferQueueHead)
  7433. {
  7434. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7435. SendContext->SetListEntryUnused();
  7436. NextListEntry = CurrentListEntry->Flink;
  7437. RpcpfInsertHeadList(NewQueueHead, CurrentListEntry);
  7438. UpperLayer->SendCancelled(SendContext);
  7439. CurrentListEntry = NextListEntry;
  7440. }
  7441. RpcpInitializeListHead(&BufferQueueHead);
  7442. Mutex.Clear();
  7443. }
  7444. RPC_STATUS HTTP2FlowControlSender::DirectSendComplete (
  7445. OUT BOOL *IsServer,
  7446. OUT BOOL *SendToRuntime,
  7447. OUT void **SendContext,
  7448. OUT BUFFER *Buffer,
  7449. OUT UINT *BufferLength
  7450. )
  7451. /*++
  7452. Routine Description:
  7453. Direct send complete notification. Complete the send
  7454. passing it only through channels that have seen it (i.e.
  7455. above us). Note that we will get one notification for
  7456. all buffered sends. We must empty the whole queue, and post
  7457. one notification for each buffer in the queue
  7458. Arguments:
  7459. IsServer - in all cases MUST be set to TRUE or FALSE.
  7460. SendToRuntime - in all cases MUST be set to TRUE or FALSE. If FALSE,
  7461. it won't be sent to the runtime (used by proxies)
  7462. SendContext - on output contains the send context as
  7463. seen by the runtime
  7464. Buffer - on output the buffer that we tried to send
  7465. BufferLength - on output the length of the buffer we tried to send
  7466. Return Value:
  7467. RPC_S_OK to return error to runtime
  7468. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  7469. RPC_S_* error - return error to runtime
  7470. --*/
  7471. {
  7472. LIST_ENTRY *CurrentListEntry;
  7473. HTTP2SendContext *CurrentSendContext;
  7474. RPC_STATUS RpcStatus;
  7475. BOOL PostAnotherReceive;
  7476. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_FLOW_CONTROL_SENDER,
  7477. !RpcpIsListEmpty(&BufferQueueHead));
  7478. *IsServer = (BOOL)(this->IsServer);
  7479. *SendToRuntime = (BOOL)(this->SendToRuntime);
  7480. // this should only get called when we are aborted. This
  7481. // ensures that we are single threaded in the code
  7482. // below
  7483. TopChannel->VerifyAborted();
  7484. CurrentListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  7485. ASSERT(CurrentListEntry != &BufferQueueHead);
  7486. CurrentSendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  7487. CurrentSendContext->SetListEntryUnused();
  7488. ASSERT(AbortStatus != RPC_S_OK);
  7489. RpcStatus = HTTP2TransportChannel::SendComplete(AbortStatus, CurrentSendContext);
  7490. PostAnotherReceive = !(RpcpIsListEmpty(&BufferQueueHead));
  7491. if ((RpcStatus != RPC_P_PACKET_CONSUMED) && this->SendToRuntime)
  7492. {
  7493. // this will return to the runtime. Make sure it is valid
  7494. if (this->IsServer)
  7495. I_RpcTransVerifyServerRuntimeCallFromContext(CurrentSendContext);
  7496. else
  7497. I_RpcTransVerifyClientRuntimeCallFromContext(CurrentSendContext);
  7498. *SendContext = CurrentSendContext;
  7499. *Buffer = CurrentSendContext->pWriteBuffer;
  7500. *BufferLength = CurrentSendContext->maxWriteBuffer;
  7501. }
  7502. else
  7503. {
  7504. // the packet was a transport packet - it won't be seen by the runtime
  7505. *SendContext = NULL;
  7506. *Buffer = NULL;
  7507. *BufferLength = 0;
  7508. }
  7509. RpcStatus = AsyncCompleteHelper(RpcStatus);
  7510. // do not touch this pointer after here unless the list was not-empty
  7511. // (which implies we still have refcounts)
  7512. if (PostAnotherReceive)
  7513. {
  7514. (void) COMMON_PostRuntimeEvent(HTTP2_FLOW_CONTROL_DIRECT_SEND,
  7515. this
  7516. );
  7517. }
  7518. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_FLOW_CONTROL_SENDER,
  7519. PostAnotherReceive);
  7520. return RpcStatus;
  7521. }
  7522. RPC_STATUS HTTP2FlowControlSender::SendInternal (
  7523. IN OUT HTTP2SendContext *SendContext,
  7524. IN BOOL IgnoreQueuedBuffers
  7525. )
  7526. /*++
  7527. Routine Description:
  7528. Send request without incrementing SendsPending counter
  7529. and without handling SendContextFlagSendLast
  7530. Arguments:
  7531. SendContext - the send context
  7532. IgnoreQueuedBuffers - if non-zero, the send will proceed even if
  7533. there are queued buffers. If FALSE, the send will be queued
  7534. if there are queued buffers.
  7535. Return Value:
  7536. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7537. --*/
  7538. {
  7539. RPC_STATUS RpcStatus;
  7540. HTTP2SendContext *LocalSendContext;
  7541. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_FLOW_CONTROL_SENDER, PtrToUlong(SendContext));
  7542. if (SendContext->TrafficType == http2ttData)
  7543. {
  7544. Mutex.Request();
  7545. // if the peer doesn't have enough window to accept this packet
  7546. // or there are queued packets and we were told not to ignore them,
  7547. // we have to queue it. Otherwise we can send it
  7548. if (
  7549. (PeerAvailableWindow < SendContext->maxWriteBuffer)
  7550. ||
  7551. (
  7552. (IgnoreQueuedBuffers == FALSE)
  7553. &&
  7554. (BufferQueueHead.Flink != &BufferQueueHead)
  7555. )
  7556. )
  7557. {
  7558. // either the receiver doesn't have enough window or
  7559. // we have pending buffers
  7560. SendContext->SetListEntryUsed();
  7561. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  7562. Mutex.Clear();
  7563. #if DBG_ERROR
  7564. DbgPrint("Flow controlling sends ...%p\n", this);
  7565. #endif
  7566. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_FLOW_CONTROL_SENDER, 0);
  7567. return RPC_S_OK;
  7568. }
  7569. else
  7570. {
  7571. // yes, update counters and continue with send
  7572. DataBytesSent += SendContext->maxWriteBuffer;
  7573. PeerAvailableWindow -= SendContext->maxWriteBuffer;
  7574. }
  7575. Mutex.Clear();
  7576. }
  7577. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  7578. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_FLOW_CONTROL_SENDER, RpcStatus);
  7579. return RpcStatus;
  7580. }
  7581. /*********************************************************************
  7582. HTTP2PingOriginator
  7583. *********************************************************************/
  7584. RPC_STATUS HTTP2PingOriginator::Send (
  7585. IN OUT HTTP2SendContext *SendContext
  7586. )
  7587. /*++
  7588. Routine Description:
  7589. Send request
  7590. Arguments:
  7591. SendContext - the send context
  7592. Return Value:
  7593. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7594. --*/
  7595. {
  7596. ConsecutivePingsOnInterval = 0;
  7597. return SendInternal(SendContext);
  7598. }
  7599. RPC_STATUS HTTP2PingOriginator::SendComplete (
  7600. IN RPC_STATUS EventStatus,
  7601. IN OUT HTTP2SendContext *SendContext
  7602. )
  7603. /*++
  7604. Routine Description:
  7605. Send complete notification. Consume packets generated by us
  7606. and forward everything else up.
  7607. Arguments:
  7608. EventStatus - the status of the send
  7609. SendContext - send context
  7610. Return Value:
  7611. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  7612. --*/
  7613. {
  7614. if ((SendContext->TrafficType == http2ttRTS)
  7615. && (TrustedIsPingPacket(SendContext->pWriteBuffer)))
  7616. {
  7617. // this is a packet we generated. Eat it up
  7618. FreeRTSPacket(SendContext);
  7619. return RPC_P_PACKET_CONSUMED;
  7620. }
  7621. return HTTP2TransportChannel::SendComplete(EventStatus, SendContext);
  7622. }
  7623. RPC_STATUS HTTP2PingOriginator::SetKeepAliveTimeout (
  7624. IN BOOL TurnOn,
  7625. IN BOOL bProtectIO,
  7626. IN KEEPALIVE_TIMEOUT_UNITS Units,
  7627. IN OUT KEEPALIVE_TIMEOUT KATime,
  7628. IN ULONG KAInterval OPTIONAL
  7629. )
  7630. /*++
  7631. Routine Description:
  7632. Change the keep alive value on the channel
  7633. Arguments:
  7634. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  7635. are turned off.
  7636. bProtectIO - non-zero if IO needs to be protected against async close
  7637. of the connection. Ignored for this function since we are always
  7638. protected when we start a new submit.
  7639. Units - in what units is KATime
  7640. KATime - how much to wait before turning on keep alives. Ignored in this
  7641. function.
  7642. KAInterval - the interval between keep alives
  7643. Return Value:
  7644. RPC_S_OK or other RPC_S_* errors for error
  7645. --*/
  7646. {
  7647. RPC_STATUS RpcStatus;
  7648. ULONG LocalNewPingInterval;
  7649. // technically the time stamp can be 0, but this would
  7650. // be extremely rare
  7651. ASSERT(LastPacketSentTimestamp);
  7652. ASSERT(Units == tuMilliseconds);
  7653. if (TurnOn == FALSE)
  7654. KeepAliveInterval = 0;
  7655. else
  7656. KeepAliveInterval = KAInterval;
  7657. LocalNewPingInterval = GetPingInterval(ConnectionTimeout,
  7658. KeepAliveInterval
  7659. );
  7660. return SetNewPingInterval(LocalNewPingInterval);
  7661. }
  7662. void HTTP2PingOriginator::Abort (
  7663. IN RPC_STATUS RpcStatus
  7664. )
  7665. /*++
  7666. Routine Description:
  7667. Abort the channel
  7668. Arguments:
  7669. RpcStatus - the error code with which we abort
  7670. Return Value:
  7671. --*/
  7672. {
  7673. HTTP2TransportChannel::Abort(RpcStatus);
  7674. // we are already synchronized with everybody. Just
  7675. // call the internal function
  7676. DisablePingsInternal();
  7677. }
  7678. void HTTP2PingOriginator::FreeObject (
  7679. void
  7680. )
  7681. /*++
  7682. Routine Description:
  7683. Frees the object. Acts like a destructor for the
  7684. channel.
  7685. Arguments:
  7686. Return Value:
  7687. --*/
  7688. {
  7689. if (LowerLayer)
  7690. LowerLayer->FreeObject();
  7691. HTTP2PingOriginator::~HTTP2PingOriginator();
  7692. }
  7693. void HTTP2PingOriginator::SendCancelled (
  7694. IN HTTP2SendContext *SendContext
  7695. )
  7696. /*++
  7697. Routine Description:
  7698. A lower channel cancelled a send already passed through this channel.
  7699. Arguments:
  7700. SendContext - the send context of the send that was cancelled
  7701. Return Value:
  7702. --*/
  7703. {
  7704. RPC_STATUS RpcStatus;
  7705. // a call was cancelled. We don't know what was the last sent
  7706. // time before that, so the only safe thing to do is send another
  7707. // ping. This should be extremely rare as it happens only sometimes
  7708. // during channel recycling.
  7709. RpcStatus = ReferenceFromCallback();
  7710. // if already aborted, don't bother
  7711. if (RpcStatus != RPC_S_OK)
  7712. return;
  7713. // we don't care about the result. The channel is dying. If we
  7714. // managed to submit the ping, it's better. If not, we hope the
  7715. // channel will last for long enough in order to complete the
  7716. // recycle process
  7717. RpcStatus = SendPingPacket();
  7718. // SendCancelled will be called only when the channel is close to the
  7719. // end of its recycling. We cannot get another recycling request here.
  7720. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  7721. TopChannel->FinishSubmitAsync();
  7722. UpperLayer->SendCancelled(SendContext);
  7723. }
  7724. void HTTP2PingOriginator::Reset (
  7725. void
  7726. )
  7727. /*++
  7728. Routine Description:
  7729. Reset the channel for next open/send/receive. This is
  7730. used in submission context only and implies there are no
  7731. pending operations on the channel. It is used on the client
  7732. during opening the connection to do quick negotiation on the
  7733. same connection instead of opening a new connection every time.
  7734. Arguments:
  7735. Return Value:
  7736. --*/
  7737. {
  7738. LastPacketSentTimestamp = 0;
  7739. LowerLayer->Reset();
  7740. }
  7741. RPC_STATUS HTTP2PingOriginator::SetConnectionTimeout (
  7742. IN ULONG ConnectionTimeout
  7743. )
  7744. /*++
  7745. Routine Description:
  7746. Sets the connection timeout for the ping channel. The ping channel
  7747. does not ping when initialized. This call starts the process. It is
  7748. synchronized with DisablePings but not with Aborts.
  7749. Arguments:
  7750. ConnectionTimeout - the connection timeout in milliseconds
  7751. Return Value:
  7752. RPC_S_OK or RPC_S_* error
  7753. --*/
  7754. {
  7755. RPC_STATUS RpcStatus;
  7756. ULONG LocalNewPingInterval;
  7757. // we don't accept anything less than the minimum timeout
  7758. if (ConnectionTimeout <= MinimumConnectionTimeout)
  7759. return RPC_S_PROTOCOL_ERROR;
  7760. // technically the time stamp can be 0, but this would
  7761. // be extremely rare
  7762. ASSERT(LastPacketSentTimestamp);
  7763. if (OverrideMinimumConnectionTimeout)
  7764. this->ConnectionTimeout = min(ConnectionTimeout, OverrideMinimumConnectionTimeout);
  7765. else
  7766. this->ConnectionTimeout = ConnectionTimeout;
  7767. LocalNewPingInterval = GetPingInterval(ConnectionTimeout,
  7768. KeepAliveInterval
  7769. );
  7770. return SetNewPingInterval(LocalNewPingInterval);
  7771. }
  7772. void HTTP2PingOriginator::DisablePings (
  7773. void
  7774. )
  7775. /*++
  7776. Routine Description:
  7777. Disables the pings for the channel. Synchronized with
  7778. SetConnectionTimeout but not with Aborts
  7779. Arguments:
  7780. Return Value:
  7781. RPC_S_OK or RPC_S_* error
  7782. --*/
  7783. {
  7784. RPC_STATUS RpcStatus;
  7785. // synchronize with aborts and then call internal
  7786. // routine
  7787. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  7788. if (RpcStatus == RPC_S_OK)
  7789. {
  7790. DisablePingsInternal();
  7791. TopChannel->FinishSubmitAsync();
  7792. }
  7793. }
  7794. void HTTP2PingOriginator::TimerCallback (
  7795. void
  7796. )
  7797. /*++
  7798. Routine Description:
  7799. Timer callback routine - a periodic timer fired.
  7800. Figure out what type of timer it was, and take
  7801. appropriate action.
  7802. N.B. We enter this routine with BeginSubmitAsync
  7803. called on this channel.
  7804. N.B. We enter this routine with one refcount on
  7805. the top channel.
  7806. Arguments:
  7807. Return Value:
  7808. --*/
  7809. {
  7810. ULONG CurrentTickCount;
  7811. ULONG LocalLastSentTickCount;
  7812. RPC_STATUS RpcStatus;
  7813. ULONG LocalPingInterval;
  7814. BOOL PingPacketSent;
  7815. LocalLastSentTickCount = LastPacketSentTimestamp;
  7816. CurrentTickCount = NtGetTickCount();
  7817. // if less than the grace period has expired since the last
  7818. // packet was sent, don't bother to send a ping
  7819. if (CurrentTickCount - LocalLastSentTickCount >= GetGracePeriod())
  7820. {
  7821. PingPacketSent = TRUE;
  7822. ConsecutivePingsOnInterval ++;
  7823. #if DBG_ERROR
  7824. DbgPrint("Timer expired. No recent activity - sending ping ...\n");
  7825. #endif
  7826. RpcStatus = SendPingPacket();
  7827. if ((RpcStatus != RPC_S_OK)
  7828. && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  7829. {
  7830. // if this fails, SendPingPacket did not take over
  7831. // the refcount. In this case we hand over the
  7832. // refcount to HTTP2_ABORT_CONNECTION which still
  7833. // needs one refcount to operate.
  7834. #if DBG_ERROR
  7835. DbgPrint("Ping failed. Aborting connection.\n");
  7836. #endif
  7837. TopChannel->FinishSubmitAsync();
  7838. // offload the aborting to a worker thread (rule 33)
  7839. (void) COMMON_PostRuntimeEvent(HTTP2_ABORT_CONNECTION,
  7840. TopChannel
  7841. );
  7842. return;
  7843. }
  7844. // if SendPingPacket succeeds, it took over
  7845. // the refcount. We have no refcount in this code path. The only
  7846. // thing that prevents a problem is that we haven't called
  7847. // FinishSubmitAsync yet. Until we call this, we cannot be
  7848. // aborted.
  7849. if (ConsecutivePingsOnInterval >= ThresholdConsecutivePingsOnInterval)
  7850. {
  7851. LocalPingInterval = ScaleBackPingInterval();
  7852. if (LocalPingInterval > PingInterval)
  7853. {
  7854. // we need to scale back. We can't do it from the timer callback, so we
  7855. // need to offload to a worker thread for this
  7856. ConsecutivePingsOnInterval = 0;
  7857. // add a reference for the offloaded work item
  7858. TopChannel->AddReference();
  7859. (void) COMMON_PostRuntimeEvent(HTTP2_RESCHEDULE_TIMER,
  7860. this
  7861. );
  7862. }
  7863. }
  7864. }
  7865. else
  7866. {
  7867. PingPacketSent = FALSE;
  7868. #if DBG_ERROR
  7869. DbgPrint("Timer expired. Recent activity on channel detected - no ping necessary\n");
  7870. #endif
  7871. }
  7872. if (PingPacketSent != FALSE)
  7873. {
  7874. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  7875. {
  7876. // we have the timer callback reference here which protects us. Once we
  7877. // offload to a worker thread, the reference doesn't hold. Add another
  7878. // reference for this.
  7879. TopChannel->AddReference();
  7880. TopChannel->FinishSubmitAsync();
  7881. // offload the recycling to a worker thread. This is necessary because
  7882. // the recycling will abort on failure which violates rule 33.
  7883. (void) COMMON_PostRuntimeEvent(HTTP2_RECYCLE_CHANNEL,
  7884. TopChannel
  7885. );
  7886. }
  7887. else
  7888. {
  7889. TopChannel->FinishSubmitAsync();
  7890. }
  7891. }
  7892. else
  7893. {
  7894. TopChannel->FinishSubmitAsync();
  7895. // drop the reference added for us by the timer callback
  7896. TopChannel->RemoveReference();
  7897. }
  7898. }
  7899. RPC_STATUS HTTP2PingOriginator::ReferenceFromCallback (
  7900. void
  7901. )
  7902. /*++
  7903. Routine Description:
  7904. References a ping originator object from the callback
  7905. routine.
  7906. Arguments:
  7907. Return Value:
  7908. RPC_S_OK or RPC_S_* error
  7909. --*/
  7910. {
  7911. return TopChannel->BeginSubmitAsync();
  7912. }
  7913. RPC_STATUS HTTP2PingOriginator::SetNewPingInterval (
  7914. IN ULONG NewPingInterval
  7915. )
  7916. /*++
  7917. Routine Description:
  7918. Puts into effect the new ping interval. This means
  7919. cancelling the old interval (if any) and setting
  7920. the timer for the new. Must NOT be called from
  7921. timer callbacks or we will deadlock.
  7922. Arguments:
  7923. NewPingInterval - the new ping interval to use
  7924. Return Value:
  7925. RPC_S_OK or RPC_S_* error
  7926. --*/
  7927. {
  7928. RPC_STATUS RpcStatus;
  7929. BOOL Result;
  7930. // the new interval is different than the old. Need to update
  7931. // and reschedule
  7932. PingInterval = NewPingInterval;
  7933. ConsecutivePingsOnInterval = 0;
  7934. // synchronize with Aborts
  7935. RpcStatus = TopChannel->BeginSimpleSubmitAsync();
  7936. if (RpcStatus != RPC_S_OK)
  7937. return RpcStatus;
  7938. if (PingTimer)
  7939. {
  7940. DisablePingsInternal();
  7941. }
  7942. Result = CreateTimerQueueTimer(&PingTimer,
  7943. NULL,
  7944. HTTP2PingTimerCallback,
  7945. this,
  7946. PingInterval, // time to first fire
  7947. PingInterval, // periodic interval
  7948. WT_EXECUTELONGFUNCTION
  7949. );
  7950. if (Result == FALSE)
  7951. {
  7952. PingTimer = NULL;
  7953. TopChannel->FinishSubmitAsync();
  7954. return RPC_S_OUT_OF_MEMORY;
  7955. }
  7956. // add one reference for the timer callback we have set up
  7957. TopChannel->AddReference();
  7958. TopChannel->FinishSubmitAsync();
  7959. return RPC_S_OK;
  7960. }
  7961. void HTTP2PingOriginator::RescheduleTimer (
  7962. void
  7963. )
  7964. /*++
  7965. Routine Description:
  7966. Reschedules a timer. This means scale back a timer.
  7967. Arguments:
  7968. Return Value:
  7969. --*/
  7970. {
  7971. ULONG LocalPingInterval;
  7972. LocalPingInterval = ScaleBackPingInterval();
  7973. if (LocalPingInterval > PingInterval)
  7974. {
  7975. // ignore the result. Scaling back is a best effort.
  7976. // If it fails, that's ok.
  7977. (void) SetNewPingInterval(LocalPingInterval);
  7978. }
  7979. // remove the reference for the work item
  7980. TopChannel->RemoveReference();
  7981. }
  7982. void HTTP2PingOriginator::DisablePingsInternal (
  7983. void
  7984. )
  7985. /*++
  7986. Routine Description:
  7987. Disables the pings for the channel. Must be synchronized with
  7988. SetConnectionTimeout, Abort and DisablePings
  7989. Arguments:
  7990. Return Value:
  7991. RPC_S_OK or RPC_S_* error
  7992. --*/
  7993. {
  7994. BOOL Result;
  7995. if (PingTimer)
  7996. {
  7997. Result = DeleteTimerQueueTimer(NULL,
  7998. PingTimer,
  7999. INVALID_HANDLE_VALUE // tell the timer function to wait for all callbacks
  8000. // to complete before returning
  8001. );
  8002. #if DBG
  8003. // during process shutdown the loader termination code will
  8004. // shutdown threads (including the NTDLL thread pool threads)
  8005. // before it indicates to anybody that it is doing so. This ASSERT
  8006. // will fire in such cases causing random stress breaks. Disable it.
  8007. // ASSERT(Result);
  8008. #endif // DBG
  8009. // we added one reference for the timer callback. Remove it
  8010. TopChannel->RemoveReference();
  8011. PingTimer = NULL;
  8012. }
  8013. }
  8014. RPC_STATUS HTTP2PingOriginator::SendPingPacket (
  8015. void
  8016. )
  8017. /*++
  8018. Routine Description:
  8019. Sends a ping packet on this channel. Must be called with AsyncSubmit
  8020. started.
  8021. Arguments:
  8022. Return Value:
  8023. RPC_S_OK or RPC_S_* error
  8024. --*/
  8025. {
  8026. RPC_STATUS RpcStatus;
  8027. HTTP2SendContext *PingPacket;
  8028. ULONG PingPacketSize;
  8029. PingPacket = AllocateAndInitializePingPacket();
  8030. if (PingPacket == NULL)
  8031. return RPC_S_OUT_OF_MEMORY;
  8032. PingPacketSize = PingPacket->maxWriteBuffer;
  8033. RpcStatus = SendInternal(PingPacket);
  8034. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  8035. FreeRTSPacket(PingPacket);
  8036. else if (NotifyTopChannelForPings)
  8037. TopChannel->PingTrafficSentNotify(PingPacketSize);
  8038. return RpcStatus;
  8039. }
  8040. RPC_STATUS HTTP2PingOriginator::SendInternal (
  8041. IN OUT HTTP2SendContext *SendContext
  8042. )
  8043. /*++
  8044. Routine Description:
  8045. Send request
  8046. Arguments:
  8047. SendContext - the send context
  8048. Return Value:
  8049. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8050. --*/
  8051. {
  8052. LastPacketSentTimestamp = NtGetTickCount();
  8053. return HTTP2TransportChannel::Send(SendContext);
  8054. }
  8055. /*********************************************************************
  8056. HTTP2PingReceiver
  8057. *********************************************************************/
  8058. RPC_STATUS HTTP2PingReceiver::ReceiveComplete (
  8059. IN RPC_STATUS EventStatus,
  8060. IN HTTP2TrafficType TrafficType,
  8061. IN BYTE *Buffer,
  8062. IN UINT BufferLength
  8063. )
  8064. /*++
  8065. Routine Description:
  8066. Receive complete notification.
  8067. Arguments:
  8068. EventStatus - status of the operation
  8069. TrafficType - the type of traffic we have received
  8070. Buffer - the received buffer (success only)
  8071. BufferLength - the length of the received buffer (success only)
  8072. Return Value:
  8073. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8074. --*/
  8075. {
  8076. if (EventStatus == RPC_S_OK)
  8077. {
  8078. if (IsRTSPacket(Buffer) && UntrustedIsPingPacket(Buffer, BufferLength))
  8079. {
  8080. // this is a ping packet. Consume it and post another receive if
  8081. // necessary
  8082. if (PostAnotherReceive)
  8083. {
  8084. EventStatus = TopChannel->BeginSubmitAsync();
  8085. if (EventStatus == RPC_S_OK)
  8086. {
  8087. EventStatus = HTTP2TransportChannel::Receive(http2ttRaw);
  8088. TopChannel->FinishSubmitAsync();
  8089. if (EventStatus != RPC_S_OK)
  8090. TopChannel->RemoveReference();
  8091. }
  8092. }
  8093. if (EventStatus == RPC_S_OK)
  8094. {
  8095. // we free the buffer only in success case. In failure case
  8096. // we need a buffer to pass to receive complete down.
  8097. RpcFreeBuffer(Buffer);
  8098. return RPC_P_PACKET_CONSUMED;
  8099. }
  8100. else
  8101. {
  8102. // fall through to indicating a receive failure below
  8103. }
  8104. }
  8105. }
  8106. return HTTP2TransportChannel::ReceiveComplete(EventStatus, TrafficType, Buffer, BufferLength);
  8107. }
  8108. void HTTP2PingReceiver::FreeObject (
  8109. void
  8110. )
  8111. /*++
  8112. Routine Description:
  8113. Frees the object. Acts like a destructor for the
  8114. channel.
  8115. Arguments:
  8116. Return Value:
  8117. --*/
  8118. {
  8119. if (LowerLayer)
  8120. LowerLayer->FreeObject();
  8121. HTTP2PingReceiver::~HTTP2PingReceiver();
  8122. }
  8123. /*********************************************************************
  8124. HTTP2ChannelDataOriginator
  8125. *********************************************************************/
  8126. HTTP2ChannelDataOriginator::HTTP2ChannelDataOriginator (
  8127. IN ULONG ChannelLifetime,
  8128. IN BOOL IsServer,
  8129. OUT RPC_STATUS *Status
  8130. ) : Mutex(Status,
  8131. FALSE, // pre-allocate semaphore
  8132. 5000 // spin count
  8133. )
  8134. /*++
  8135. Routine Description:
  8136. HTTP2ChannelDataOriginator constructor
  8137. Arguments:
  8138. ChannelLifetime - the lifetime read from the registry
  8139. IsServer - non-zero if this is a server side data originator.
  8140. 0 otherwise.
  8141. Status - on input RPC_S_OK. On output, the result of the constructor.
  8142. Return Value:
  8143. --*/
  8144. {
  8145. RpcpInitializeListHead(&BufferQueueHead);
  8146. this->ChannelLifetime = ChannelLifetime;
  8147. NonreservedLifetime = ChannelLifetime;
  8148. if (IsServer)
  8149. NonreservedLifetime -= ServerReservedChannelLifetime;
  8150. else
  8151. NonreservedLifetime -= ClientReservedChannelLifetime;
  8152. this->IsServer = IsServer;
  8153. BytesSentOnChannel = 0;
  8154. ChannelReplacementTriggered = FALSE;
  8155. AbortStatus = RPC_S_OK;
  8156. #if DBG
  8157. RawDataAlreadySent = FALSE;
  8158. #endif // DBG
  8159. }
  8160. RPC_STATUS HTTP2ChannelDataOriginator::Send (
  8161. IN OUT HTTP2SendContext *SendContext
  8162. )
  8163. /*++
  8164. Routine Description:
  8165. Send request
  8166. Arguments:
  8167. SendContext - the send context
  8168. Return Value:
  8169. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8170. --*/
  8171. {
  8172. ULONG NewBytesSentOnChannel;
  8173. BOOL ChannelReplacementNeeded;
  8174. RPC_STATUS RpcStatus;
  8175. ULONG LocalBytesSentOnChannel;
  8176. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  8177. ChannelReplacementNeeded = FALSE;
  8178. // if this is raw traffic, don't count it
  8179. if (SendContext->TrafficType == http2ttRaw)
  8180. {
  8181. RawDataBeingSent();
  8182. }
  8183. // otherwise, count it only if the traffic is not specifically exempt
  8184. else if ((SendContext->Flags & SendContextFlagNonChannelData) == 0)
  8185. {
  8186. // we don't always take the mutex. We know that the bytes sent will only
  8187. // grow. If we think it is a good time to recycle the channel, the fact that
  8188. // another thread is also sending in a race condition with us makes it even
  8189. // more so. We just need to be careful to properly update the BytesSendOnChannel
  8190. // at the end
  8191. LocalBytesSentOnChannel = BytesSentOnChannel;
  8192. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  8193. if ((NewBytesSentOnChannel > NonreservedLifetime) || ChannelReplacementTriggered)
  8194. {
  8195. Mutex.Request();
  8196. // now that we have the mutex, check again. Sometimes the channel
  8197. // can start sending from 0 again (e.g. out proxy negotiates a new
  8198. // out channel with the client and server is ready to start from 0)
  8199. // This can happen in restart channel, which is also protected by the
  8200. // mutex
  8201. LocalBytesSentOnChannel = BytesSentOnChannel;
  8202. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  8203. if ((NewBytesSentOnChannel > NonreservedLifetime) || ChannelReplacementTriggered)
  8204. {
  8205. if (ChannelReplacementTriggered == FALSE)
  8206. {
  8207. ChannelReplacementNeeded = TRUE;
  8208. ChannelReplacementTriggered = TRUE;
  8209. }
  8210. // if this is data, queue it
  8211. if (SendContext->TrafficType == http2ttData)
  8212. {
  8213. SendContext->SetListEntryUsed();
  8214. RpcpfInsertTailList(&BufferQueueHead, &SendContext->ListEntry);
  8215. Mutex.Clear();
  8216. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  8217. if (ChannelReplacementNeeded)
  8218. {
  8219. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHANNEL_RECYCLE, HTTP2LOG_OT_CDATA_ORIGINATOR, NewBytesSentOnChannel);
  8220. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  8221. }
  8222. else
  8223. return RPC_S_OK;
  8224. }
  8225. else
  8226. {
  8227. ASSERT(SendContext->TrafficType == http2ttRTS);
  8228. // fall through to sending below
  8229. }
  8230. }
  8231. Mutex.Clear();
  8232. // either channel got reset or this was RTS traffic. Fall through to
  8233. // sending
  8234. }
  8235. // update BytesSentOnChannel in thread safe manner
  8236. do
  8237. {
  8238. LocalBytesSentOnChannel = BytesSentOnChannel;
  8239. NewBytesSentOnChannel = LocalBytesSentOnChannel + SendContext->maxWriteBuffer;
  8240. }
  8241. while (InterlockedCompareExchange((LONG *)&BytesSentOnChannel,
  8242. NewBytesSentOnChannel,
  8243. LocalBytesSentOnChannel) != LocalBytesSentOnChannel);
  8244. }
  8245. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  8246. if (ChannelReplacementNeeded && (RpcStatus == RPC_S_OK))
  8247. {
  8248. #if DBG
  8249. DbgPrintEx(DPFLTR_RPCPROXY_ID,
  8250. DPFLTR_TRACE_LEVEL,
  8251. "RPCRT4: Indicating channel needs recycling %p %d\n",
  8252. this,
  8253. IsServer);
  8254. #endif // DBG
  8255. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHANNEL_RECYCLE, HTTP2LOG_OT_CDATA_ORIGINATOR, NewBytesSentOnChannel);
  8256. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  8257. }
  8258. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CDATA_ORIGINATOR, BytesSentOnChannel);
  8259. return RpcStatus;
  8260. }
  8261. void HTTP2ChannelDataOriginator::Abort (
  8262. IN RPC_STATUS RpcStatus
  8263. )
  8264. {
  8265. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CDATA_ORIGINATOR, RpcStatus);
  8266. // we have a bunch of sends carrying ref-counts, etc.
  8267. // We must make sure they are completed.
  8268. HTTP2TransportChannel::Abort(RpcStatus);
  8269. // we know we are synchronized with everybody else
  8270. if (!RpcpIsListEmpty(&BufferQueueHead))
  8271. {
  8272. AbortStatus = RpcStatus;
  8273. (void) COMMON_PostRuntimeEvent(CHANNEL_DATA_ORIGINATOR_DIRECT_SEND,
  8274. this
  8275. );
  8276. }
  8277. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CDATA_ORIGINATOR, RpcStatus);
  8278. }
  8279. void HTTP2ChannelDataOriginator::FreeObject (
  8280. void
  8281. )
  8282. /*++
  8283. Routine Description:
  8284. Frees the object. Acts like a destructor for the
  8285. channel.
  8286. Arguments:
  8287. Return Value:
  8288. --*/
  8289. {
  8290. if (LowerLayer)
  8291. LowerLayer->FreeObject();
  8292. HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  8293. }
  8294. void HTTP2ChannelDataOriginator::Reset (
  8295. void
  8296. )
  8297. /*++
  8298. Routine Description:
  8299. Reset the channel for next open/send/receive. This is
  8300. used in submission context only and implies there are no
  8301. pending operations on the channel. It is used on the client
  8302. during opening the connection to do quick negotiation on the
  8303. same connection instead of opening a new connection every time.
  8304. Arguments:
  8305. Return Value:
  8306. --*/
  8307. {
  8308. #if DBG
  8309. RawDataAlreadySent = FALSE;
  8310. #endif // DBG
  8311. ASSERT(RpcpIsListEmpty(&BufferQueueHead));
  8312. LowerLayer->Reset();
  8313. }
  8314. void HTTP2ChannelDataOriginator::GetBufferQueue (
  8315. OUT LIST_ENTRY *NewQueueHead
  8316. )
  8317. /*++
  8318. Routine Description:
  8319. Grab all queued buffers and pile them on the list head
  8320. that we passed to it. All refcounts must be removed (i.e.
  8321. undone). Called in submission context only and we know there
  8322. will be no more sends. Therefore we are single threaded.
  8323. Arguments:
  8324. NewQueueHead - new queue heads to pile buffers on
  8325. Return Value:
  8326. --*/
  8327. {
  8328. LIST_ENTRY *CurrentListEntry;
  8329. LIST_ENTRY *NextListEntry;
  8330. HTTP2SendContext *SendContext;
  8331. ASSERT(RpcpIsListEmpty(NewQueueHead));
  8332. CurrentListEntry = BufferQueueHead.Flink;
  8333. while (CurrentListEntry != &BufferQueueHead)
  8334. {
  8335. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  8336. SendContext->SetListEntryUnused();
  8337. NextListEntry = CurrentListEntry->Flink;
  8338. RpcpfInsertHeadList(NewQueueHead, CurrentListEntry);
  8339. UpperLayer->SendCancelled(SendContext);
  8340. CurrentListEntry = NextListEntry;
  8341. }
  8342. RpcpInitializeListHead(&BufferQueueHead);
  8343. }
  8344. RPC_STATUS HTTP2ChannelDataOriginator::DirectSendComplete (
  8345. OUT BOOL *IsServer,
  8346. OUT void **SendContext,
  8347. OUT BUFFER *Buffer,
  8348. OUT UINT *BufferLength
  8349. )
  8350. /*++
  8351. Routine Description:
  8352. Direct send complete notification. Complete the send
  8353. passing it only through channels that have seen it (i.e.
  8354. above us). Note that we will get one notification for
  8355. all buffered sends. We must empty the whole queue, and post
  8356. one notification for each buffer in the queue
  8357. Arguments:
  8358. IsServer - in all cases MUST be set to TRUE or FALSE.
  8359. SendContext - on output contains the send context as
  8360. seen by the runtime
  8361. Buffer - on output the buffer that we tried to send
  8362. BufferLength - on output the length of the buffer we tried to send
  8363. Return Value:
  8364. RPC_S_OK to return error to runtime
  8365. RPC_P_PACKET_CONSUMED - to hide packet from runtime
  8366. RPC_S_* error - return error to runtime
  8367. --*/
  8368. {
  8369. LIST_ENTRY *CurrentListEntry;
  8370. HTTP2SendContext *CurrentSendContext;
  8371. RPC_STATUS RpcStatus;
  8372. BOOL PostAnotherReceive;
  8373. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_CDATA_ORIGINATOR,
  8374. !RpcpIsListEmpty(&BufferQueueHead));
  8375. *IsServer = this->IsServer;
  8376. // this should only get called when we are aborted. This
  8377. // ensures that we are single threaded in the code
  8378. // below
  8379. TopChannel->VerifyAborted();
  8380. CurrentListEntry = RpcpfRemoveHeadList(&BufferQueueHead);
  8381. ASSERT(CurrentListEntry != &BufferQueueHead);
  8382. CurrentSendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  8383. CurrentSendContext->SetListEntryUnused();
  8384. ASSERT(AbortStatus != RPC_S_OK);
  8385. RpcStatus = HTTP2TransportChannel::SendComplete(AbortStatus, CurrentSendContext);
  8386. PostAnotherReceive = !(RpcpIsListEmpty(&BufferQueueHead));
  8387. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8388. {
  8389. // this will return to the runtime. Make sure it is valid
  8390. if (this->IsServer)
  8391. I_RpcTransVerifyServerRuntimeCallFromContext(CurrentSendContext);
  8392. else
  8393. I_RpcTransVerifyClientRuntimeCallFromContext(CurrentSendContext);
  8394. *SendContext = CurrentSendContext;
  8395. *Buffer = CurrentSendContext->pWriteBuffer;
  8396. *BufferLength = CurrentSendContext->maxWriteBuffer;
  8397. }
  8398. else
  8399. {
  8400. // the packet was a transport packet - it won't be seen by the runtime
  8401. *SendContext = NULL;
  8402. *Buffer = NULL;
  8403. *BufferLength = 0;
  8404. }
  8405. RpcStatus = AsyncCompleteHelper(RpcStatus);
  8406. // do not touch this pointer after here unless the list was not-empty
  8407. // (which implies we still have refcounts)
  8408. if (PostAnotherReceive)
  8409. {
  8410. (void) COMMON_PostRuntimeEvent(CHANNEL_DATA_ORIGINATOR_DIRECT_SEND,
  8411. this
  8412. );
  8413. }
  8414. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_DIRECT_SEND_COMPLETE, HTTP2LOG_OT_CDATA_ORIGINATOR,
  8415. PostAnotherReceive);
  8416. return RpcStatus;
  8417. }
  8418. RPC_STATUS HTTP2ChannelDataOriginator::RestartChannel (
  8419. void
  8420. )
  8421. /*++
  8422. Routine Description:
  8423. Restart the channel. Somehow the channel lifetime became
  8424. fully available again, and we can start from 0. This happens
  8425. when the out proxy renegotiates the out channel with the client
  8426. and we can keep using the server channels again.
  8427. Arguments:
  8428. Return Value:
  8429. RPC_S_OK
  8430. RPC_S_* error
  8431. --*/
  8432. {
  8433. LIST_ENTRY *CurrentListEntry;
  8434. HTTP2SendContext *SendContext;
  8435. ULONG NewBytesSentOnChannel = 0;
  8436. ULONG BytesForThisSend;
  8437. RPC_STATUS RpcStatus;
  8438. // the channel must have been plugged
  8439. ASSERT(BytesSentOnChannel > NonreservedLifetime);
  8440. Mutex.Request();
  8441. // grab all queued packets and send them out
  8442. CurrentListEntry = BufferQueueHead.Flink;
  8443. while (CurrentListEntry != &BufferQueueHead)
  8444. {
  8445. SendContext = CONTAINING_RECORD(CurrentListEntry, HTTP2SendContext, ListEntry);
  8446. SendContext->SetListEntryUnused();
  8447. ASSERT(SendContext->TrafficType == http2ttData);
  8448. BytesForThisSend = SendContext->maxWriteBuffer;
  8449. // assume success of the send and remove the element from the queue.
  8450. // This is necessary because if the send succeeds, there is a race
  8451. // condition with the send complete path
  8452. (void) RpcpfRemoveHeadList(&BufferQueueHead);
  8453. RpcStatus = HTTP2TransportChannel::Send(SendContext);
  8454. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  8455. if (RpcStatus != RPC_S_OK)
  8456. {
  8457. // failure. We should issue send complete for all queued sends
  8458. // including the current one. However, it is easier for us to add back
  8459. // the currently failed send and return failure to caller. Caller will
  8460. // abort and there we will issue send complete for all pending sends.
  8461. SendContext->SetListEntryUsed();
  8462. RpcpfInsertHeadList(&BufferQueueHead, CurrentListEntry);
  8463. Mutex.Clear();
  8464. // return failure to the caller. This will cause the caller to abort the
  8465. // channel, and all sends will be completed.
  8466. return RpcStatus;
  8467. }
  8468. NewBytesSentOnChannel += BytesForThisSend;
  8469. ASSERT(NewBytesSentOnChannel < NonreservedLifetime);
  8470. // process the next element (which by now has become the first since
  8471. // we removed the successfully sent one).
  8472. CurrentListEntry = BufferQueueHead.Flink;
  8473. }
  8474. // reset the counters
  8475. ChannelReplacementTriggered = FALSE;
  8476. BytesSentOnChannel = NewBytesSentOnChannel;
  8477. Mutex.Clear();
  8478. return RPC_S_OK;
  8479. }
  8480. RPC_STATUS HTTP2ChannelDataOriginator::NotifyTrafficSent (
  8481. IN ULONG TrafficSentSize
  8482. )
  8483. /*++
  8484. Routine Description:
  8485. Notifies the channel that bytes were sent on the wire. Channel
  8486. reports back whether channel recycling should occur.
  8487. Arguments:
  8488. TrafficSentSize - the number of bytes sent.
  8489. Return Value:
  8490. RPC_S_OK or RPC_P_CHANNEL_NEEDS_RECYCLING.
  8491. --*/
  8492. {
  8493. ULONG LocalBytesSentOnChannel;
  8494. ULONG NewBytesSentOnChannel;
  8495. BOOL ChannelReplacementNeeded;
  8496. ChannelReplacementNeeded = FALSE;
  8497. // this is very rare. Don't bother to take the mutex opportunistically.
  8498. // Just make sure that we do use interlocks because no all paths take
  8499. // the mutex. The mutex synchronizes us with Restart
  8500. Mutex.Request();
  8501. LocalBytesSentOnChannel = BytesSentOnChannel;
  8502. NewBytesSentOnChannel = LocalBytesSentOnChannel + TrafficSentSize;
  8503. if (NewBytesSentOnChannel > NonreservedLifetime)
  8504. {
  8505. if (ChannelReplacementTriggered == FALSE)
  8506. {
  8507. ChannelReplacementNeeded = TRUE;
  8508. ChannelReplacementTriggered = TRUE;
  8509. }
  8510. }
  8511. Mutex.Clear();
  8512. // update BytesSentOnChannel in thread safe manner
  8513. do
  8514. {
  8515. LocalBytesSentOnChannel = BytesSentOnChannel;
  8516. NewBytesSentOnChannel = LocalBytesSentOnChannel + TrafficSentSize;
  8517. }
  8518. while (InterlockedCompareExchange((LONG *)&BytesSentOnChannel,
  8519. NewBytesSentOnChannel,
  8520. LocalBytesSentOnChannel) != LocalBytesSentOnChannel);
  8521. if (ChannelReplacementNeeded)
  8522. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  8523. else
  8524. return RPC_S_OK;
  8525. }
  8526. /*********************************************************************
  8527. HTTP2Channel
  8528. *********************************************************************/
  8529. RPC_STATUS HTTP2Channel::Send (
  8530. IN OUT HTTP2SendContext *SendContext
  8531. )
  8532. /*++
  8533. Routine Description:
  8534. Send request
  8535. Arguments:
  8536. SendContext - the send context
  8537. Return Value:
  8538. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8539. --*/
  8540. {
  8541. RPC_STATUS RpcStatus;
  8542. if (SendContext->Flags & SendContextFlagPluggedChannel)
  8543. {
  8544. BeginSubmitAsyncNonFailing();
  8545. }
  8546. else
  8547. {
  8548. RpcStatus = BeginSubmitAsync();
  8549. if (RpcStatus != RPC_S_OK)
  8550. return RpcStatus;
  8551. }
  8552. RpcStatus = LowerLayer->Send(SendContext);
  8553. FinishSubmitAsync();
  8554. if ((RpcStatus != RPC_S_OK)
  8555. && (RpcStatus != ERROR_IO_PENDING)
  8556. && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  8557. {
  8558. RemoveReference(); // remove the reference for the async send
  8559. }
  8560. return(RpcStatus);
  8561. }
  8562. RPC_STATUS HTTP2Channel::Receive (
  8563. IN HTTP2TrafficType TrafficType
  8564. )
  8565. /*++
  8566. Routine Description:
  8567. Receive request
  8568. Arguments:
  8569. TrafficType - the type of traffic we want to receive
  8570. Return Value:
  8571. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8572. --*/
  8573. {
  8574. RPC_STATUS RpcStatus;
  8575. RpcStatus = BeginSubmitAsync();
  8576. if (RpcStatus != RPC_S_OK)
  8577. return RpcStatus;
  8578. RpcStatus = LowerLayer->Receive(TrafficType);
  8579. FinishSubmitAsync();
  8580. if (RpcStatus != RPC_S_OK)
  8581. RemoveReference(); // remove the reference for the async receive
  8582. return(RpcStatus);
  8583. }
  8584. RPC_STATUS HTTP2Channel::SendComplete (
  8585. IN RPC_STATUS EventStatus,
  8586. IN OUT HTTP2SendContext *SendContext
  8587. )
  8588. /*++
  8589. Routine Description:
  8590. Send complete notification
  8591. Arguments:
  8592. EventStatus - status of the operation
  8593. SendContext - the send context
  8594. Return Value:
  8595. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8596. --*/
  8597. {
  8598. RPC_STATUS RpcStatus;
  8599. RpcStatus = CheckSendCompleteForSync(EventStatus,
  8600. SendContext
  8601. );
  8602. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8603. {
  8604. RpcStatus = ForwardUpSendComplete(EventStatus,
  8605. SendContext
  8606. );
  8607. }
  8608. return RpcStatus;
  8609. }
  8610. RPC_STATUS HTTP2Channel::ReceiveComplete (
  8611. IN RPC_STATUS EventStatus,
  8612. IN HTTP2TrafficType TrafficType,
  8613. IN BYTE *Buffer,
  8614. IN UINT BufferLength
  8615. )
  8616. /*++
  8617. Routine Description:
  8618. Receive complete notification complete notification
  8619. Arguments:
  8620. EventStatus - status of the operation
  8621. TrafficType - the type of traffic we have received
  8622. Buffer - the received buffer (success only)
  8623. BufferLength - the length of the received buffer (success only)
  8624. Return Value:
  8625. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8626. --*/
  8627. {
  8628. RPC_STATUS RpcStatus;
  8629. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_CHANNEL, (ULONG_PTR)EventStatus);
  8630. RpcStatus = CheckReceiveCompleteForSync(EventStatus,
  8631. TrafficType,
  8632. Buffer,
  8633. BufferLength
  8634. );
  8635. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  8636. {
  8637. RpcStatus = ForwardUpReceiveComplete(EventStatus,
  8638. Buffer,
  8639. BufferLength
  8640. );
  8641. }
  8642. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_RECV_COMPLETE, HTTP2LOG_OT_CHANNEL, (ULONG_PTR)RpcStatus);
  8643. return RpcStatus;
  8644. }
  8645. void HTTP2Channel::PrepareForSyncSend (
  8646. IN ULONG BufferLength,
  8647. IN BYTE *Buffer,
  8648. IN OUT HTTP2SendContext *SendContext
  8649. )
  8650. /*++
  8651. Routine Description:
  8652. Prepares a SendContext for SyncSend
  8653. Arguments:
  8654. BufferLength - the length of the buffer
  8655. Buffer - the buffer to send
  8656. SendContext - a memory block of sufficient size to initialize a send context
  8657. Return Value:
  8658. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8659. --*/
  8660. {
  8661. SendContext->u.SyncEvent = I_RpcTransGetThreadEvent();
  8662. ResetEvent(SendContext->u.SyncEvent);
  8663. SendContext->SetListEntryUnused();
  8664. SendContext->maxWriteBuffer = BufferLength;
  8665. SendContext->pWriteBuffer = Buffer;
  8666. // SendContext->Write.pAsyncObject = NULL; // this will be initialized in the bottom layer
  8667. SendContext->Write.ol.Internal = STATUS_PENDING;
  8668. SendContext->TrafficType = http2ttData;
  8669. SendContext->Write.ol.OffsetHigh = 0;
  8670. SendContext->Flags = 0;
  8671. SendContext->UserData = 0;
  8672. }
  8673. RPC_STATUS HTTP2Channel::SyncSend (
  8674. IN HTTP2TrafficType TrafficType,
  8675. IN ULONG BufferLength,
  8676. IN BYTE *Buffer,
  8677. IN BOOL fDisableCancelCheck,
  8678. IN ULONG Timeout,
  8679. IN BASE_ASYNC_OBJECT *Connection,
  8680. IN HTTP2SendContext *SendContext
  8681. )
  8682. /*++
  8683. Routine Description:
  8684. Emulate a sync send using lower level async primitives
  8685. Arguments:
  8686. TrafficType - the type of traffic
  8687. BufferLength - the length of the buffer
  8688. Buffer - the buffer to send
  8689. fDisableCancelCheck - don't do checks for cancels. Can be
  8690. used as optimization
  8691. Timeout - the call timeout
  8692. Connection - the transport connection object. Used for cancelling.
  8693. SendContext - a memory block of sufficient size to initialize a send context
  8694. Return Value:
  8695. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8696. --*/
  8697. {
  8698. RPC_STATUS RpcStatus;
  8699. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CHANNEL, 0);
  8700. PrepareForSyncSend (BufferLength,
  8701. Buffer,
  8702. SendContext);
  8703. RpcStatus = HTTP2Channel::Send(SendContext);
  8704. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_CHANNEL, RpcStatus);
  8705. return RpcStatus;
  8706. }
  8707. RPC_STATUS HTTP2Channel::ForwardTraffic (
  8708. IN BYTE *Packet,
  8709. IN ULONG PacketLength
  8710. )
  8711. /*++
  8712. Routine Description:
  8713. On receiving channels forwards to the sending channel.
  8714. On sending channels sends down. This implementation
  8715. is for a sending channel (since all sending channels
  8716. are the same). Receiving channels must override it.
  8717. Arguments:
  8718. Packet - the packet to forward
  8719. PacketLength - the length of the packet
  8720. Return Value:
  8721. RPC_S_OK or other RPC_S_* errors for error
  8722. --*/
  8723. {
  8724. HTTP2SendContext *SendContext;
  8725. SendContext = AllocateAndInitializeContextFromPacket(Packet,
  8726. PacketLength
  8727. );
  8728. if (SendContext != NULL)
  8729. {
  8730. return Send(SendContext);
  8731. }
  8732. else
  8733. return RPC_S_OUT_OF_MEMORY;
  8734. }
  8735. RPC_STATUS HTTP2Channel::ForwardFlowControlAck (
  8736. IN ULONG BytesReceivedForAck,
  8737. IN ULONG WindowForAck
  8738. )
  8739. /*++
  8740. Routine Description:
  8741. Forwards a flow control ack. Receiving channels don't
  8742. need this. Sending channels must override to forward
  8743. to the right place.
  8744. Arguments:
  8745. BytesReceivedForAck - the bytes received when the ACK was issued
  8746. WindowForAck - the free window when the ACK was issued.
  8747. Return Value:
  8748. RPC_S_OK or RPC_S_*
  8749. --*/
  8750. {
  8751. // we should never be here
  8752. ASSERT(0);
  8753. return RPC_S_INTERNAL_ERROR;
  8754. }
  8755. RPC_STATUS HTTP2Channel::AsyncCompleteHelper (
  8756. IN RPC_STATUS CurrentStatus
  8757. )
  8758. /*++
  8759. Routine Description:
  8760. Helper routine that helps complete an async operation
  8761. Arguments:
  8762. CurrentStatus - the current status of the operation
  8763. Return Value:
  8764. The status to return to the runtime.
  8765. --*/
  8766. {
  8767. HTTP2VirtualConnection *VirtualConnection;
  8768. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  8769. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  8770. if (CurrentStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  8771. {
  8772. // recycle the parent connection
  8773. VirtualConnection = LockParentPointer();
  8774. if (VirtualConnection)
  8775. {
  8776. CurrentStatus = VirtualConnection->RecycleChannel(
  8777. TRUE // IsFromUpcall
  8778. );
  8779. UnlockParentPointer();
  8780. }
  8781. else
  8782. {
  8783. CurrentStatus = RPC_S_OK;
  8784. }
  8785. }
  8786. else if ((CurrentStatus != RPC_S_OK)
  8787. &&
  8788. (CurrentStatus != RPC_P_PACKET_CONSUMED))
  8789. {
  8790. // if this failed, abort the whole connection
  8791. AbortConnection(CurrentStatus);
  8792. }
  8793. RemoveReference();
  8794. return CurrentStatus;
  8795. }
  8796. void HTTP2Channel::Abort (
  8797. IN RPC_STATUS RpcStatus
  8798. )
  8799. /*++
  8800. Routine Description:
  8801. Aborts the channel and all of the stack below it. The
  8802. request must come from above or from neutral context -
  8803. never from submit context from below. Otherwise we
  8804. will deadlock when we drain the upcalls
  8805. Arguments:
  8806. RpcStatus - the error to abort with
  8807. Return Value:
  8808. --*/
  8809. {
  8810. BOOL Result;
  8811. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CHANNEL, RpcStatus);
  8812. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  8813. Result = InitiateAbort();
  8814. if (Result)
  8815. {
  8816. SetAbortReason(RpcStatus);
  8817. // forward it down
  8818. LowerLayer->Abort(RpcStatus);
  8819. }
  8820. }
  8821. void HTTP2Channel::AbortConnection (
  8822. IN RPC_STATUS AbortReason
  8823. )
  8824. /*++
  8825. Routine Description:
  8826. Aborts the virtual connection.
  8827. Arguments:
  8828. RpcStatus - the error to abort with
  8829. Return Value:
  8830. --*/
  8831. {
  8832. HTTP2VirtualConnection *VirtualConnection;
  8833. // abort the parent connection
  8834. VirtualConnection = LockParentPointer();
  8835. if (VirtualConnection)
  8836. {
  8837. VirtualConnection->AbortChannels(AbortReason);
  8838. UnlockParentPointer();
  8839. }
  8840. else
  8841. {
  8842. // abort this channel at least
  8843. Abort(AbortReason);
  8844. }
  8845. }
  8846. void HTTP2Channel::AbortAndDestroyConnection (
  8847. IN RPC_STATUS AbortStatus
  8848. )
  8849. /*++
  8850. Routine Description:
  8851. Aborts and destroys the virtual connection.
  8852. Arguments:
  8853. AbortStatus - the status to abort the connection
  8854. with.
  8855. Return Value:
  8856. Note: The method is idempotent
  8857. --*/
  8858. {
  8859. HTTP2VirtualConnection *VirtualConnection;
  8860. BOOL Result;
  8861. // first, tell connection to destroy itself (almost entirely)
  8862. VirtualConnection = LockParentPointer();
  8863. if (VirtualConnection == NULL)
  8864. {
  8865. // abort ourselves at least
  8866. Abort(AbortStatus);
  8867. return;
  8868. }
  8869. Result = VirtualConnection->AbortAndDestroy(TRUE, // IsFromChannel
  8870. ChannelId,
  8871. AbortStatus);
  8872. UnlockParentPointer();
  8873. // if somebody is already destroying it, just return
  8874. if (Result == FALSE)
  8875. return;
  8876. // because we have called AbortAndDestroy, we know the connection
  8877. // will stay for us. Synchronize with upcalls from this channel
  8878. DrainUpcallsAndFreeParent();
  8879. // now VirtualConnection is a pointer disconnected from everybody
  8880. // that we can destroy at our leisure
  8881. delete VirtualConnection;
  8882. }
  8883. RPC_STATUS HTTP2Channel::CheckSendCompleteForSync (
  8884. IN RPC_STATUS EventStatus,
  8885. IN OUT HTTP2SendContext *SendContext
  8886. )
  8887. /*++
  8888. Routine Description:
  8889. Send complete notification. Checks for sync operation,
  8890. and if yes, completes the sync send and consumes
  8891. the packet.
  8892. Arguments:
  8893. EventStatus - status of the operation
  8894. SendContext - the send context
  8895. Return Value:
  8896. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8897. --*/
  8898. {
  8899. // was this a sync send?
  8900. if (SendContext->u.SyncEvent)
  8901. {
  8902. // yes, consume it
  8903. SendContext->Write.ol.Internal = (ULONG)EventStatus;
  8904. SendContext->Write.ol.OffsetHigh = 1;
  8905. SetEvent(SendContext->u.SyncEvent);
  8906. return RPC_P_PACKET_CONSUMED;
  8907. }
  8908. return RPC_S_OK;
  8909. }
  8910. RPC_STATUS HTTP2Channel::ForwardUpSendComplete (
  8911. IN RPC_STATUS EventStatus,
  8912. IN OUT HTTP2SendContext *SendContext
  8913. )
  8914. /*++
  8915. Routine Description:
  8916. Send complete notification. Forwards the send complete to the
  8917. virtual connection.
  8918. Arguments:
  8919. EventStatus - status of the operation
  8920. SendContext - the send context
  8921. Return Value:
  8922. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8923. --*/
  8924. {
  8925. HTTP2VirtualConnection *VirtualConnection;
  8926. RPC_STATUS RpcStatus;
  8927. BOOL IsRTSPacket;
  8928. VirtualConnection = LockParentPointer();
  8929. // if parent has already detached, just return back
  8930. if (VirtualConnection == NULL)
  8931. {
  8932. // in some cases the parent will detach without aborting
  8933. if (EventStatus == RPC_S_OK)
  8934. {
  8935. if (SendContext->TrafficType == http2ttRTS)
  8936. RpcStatus = RPC_P_PACKET_CONSUMED;
  8937. else
  8938. RpcStatus = EventStatus; // already ok
  8939. }
  8940. else
  8941. {
  8942. // Abort in these cases (Abort is idempotent)
  8943. Abort(EventStatus);
  8944. RpcStatus = EventStatus;
  8945. }
  8946. IsRTSPacket = (SendContext->TrafficType == http2ttRTS);
  8947. // if we have data sends pending, and we are an endpoint,
  8948. // we shouldn't have disconnected
  8949. if (Flags.GetFlag(ProxyChannelType) == FALSE)
  8950. {
  8951. ASSERT(IsRTSPacket);
  8952. }
  8953. FreeSendContextAndPossiblyData(SendContext);
  8954. if (IsRTSPacket)
  8955. return RPC_P_PACKET_CONSUMED;
  8956. else
  8957. return RpcStatus;
  8958. }
  8959. RpcStatus = VirtualConnection->SendComplete(EventStatus,
  8960. SendContext,
  8961. ChannelId
  8962. );
  8963. UnlockParentPointer();
  8964. return RpcStatus;
  8965. }
  8966. RPC_STATUS HTTP2Channel::CheckReceiveCompleteForSync (
  8967. IN RPC_STATUS EventStatus,
  8968. IN HTTP2TrafficType TrafficType,
  8969. IN BYTE *Buffer,
  8970. IN UINT BufferLength
  8971. )
  8972. /*++
  8973. Routine Description:
  8974. Receive complete notification. Checks if the receive was
  8975. sync, and if yes, fires event and consumes the packet. For
  8976. base class it's always not for us (base class does not
  8977. support sync receives)
  8978. Arguments:
  8979. EventStatus - status of the operation
  8980. TrafficType - the type of traffic we received
  8981. Buffer - the received buffer (success only)
  8982. BufferLength - the length of the received buffer (success only)
  8983. Return Value:
  8984. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  8985. --*/
  8986. {
  8987. // not for us after all. Let it continue
  8988. return RPC_S_OK;
  8989. }
  8990. RPC_STATUS HTTP2Channel::ForwardUpReceiveComplete (
  8991. IN RPC_STATUS EventStatus,
  8992. IN BYTE *Buffer,
  8993. IN UINT BufferLength
  8994. )
  8995. /*++
  8996. Routine Description:
  8997. Receive complete notification. Forwards the receive
  8998. complete to the virtual connection
  8999. Arguments:
  9000. EventStatus - status of the operation
  9001. Buffer - the received buffer (success only)
  9002. BufferLength - the length of the received buffer (success only)
  9003. Return Value:
  9004. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9005. --*/
  9006. {
  9007. HTTP2VirtualConnection *VirtualConnection;
  9008. RPC_STATUS RpcStatus;
  9009. VirtualConnection = LockParentPointer();
  9010. // if parent has already detached, just return back
  9011. if (VirtualConnection == NULL)
  9012. {
  9013. // in some cases the parent will detach without aborting
  9014. // Abort in these cases (Abort is idempotent)
  9015. Abort(RPC_P_CONNECTION_SHUTDOWN);
  9016. return RPC_P_PACKET_CONSUMED;
  9017. }
  9018. RpcStatus = VirtualConnection->ReceiveComplete(EventStatus,
  9019. Buffer,
  9020. BufferLength,
  9021. ChannelId
  9022. );
  9023. UnlockParentPointer();
  9024. if (RpcStatus == RPC_P_ABORT_NEEDED)
  9025. {
  9026. // in some cases the parent cannot abort because the channel
  9027. // is already detached from the parent. In such cases it will
  9028. // tell us to abort. (Abort is idempotent)
  9029. Abort(RPC_P_CONNECTION_SHUTDOWN);
  9030. RpcStatus = RPC_P_PACKET_CONSUMED;
  9031. }
  9032. return RpcStatus;
  9033. }
  9034. RPC_STATUS HTTP2Channel::SetKeepAliveTimeout (
  9035. IN BOOL TurnOn,
  9036. IN BOOL bProtectIO,
  9037. IN KEEPALIVE_TIMEOUT_UNITS Units,
  9038. IN OUT KEEPALIVE_TIMEOUT KATime,
  9039. IN ULONG KAInterval OPTIONAL
  9040. )
  9041. /*++
  9042. Routine Description:
  9043. Change the keep alive value on the channel
  9044. Arguments:
  9045. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  9046. are turned off.
  9047. bProtectIO - non-zero if IO needs to be protected against async close
  9048. of the connection.
  9049. Units - in what units is KATime
  9050. KATime - how much to wait before turning on keep alives
  9051. KAInterval - the interval between keep alives
  9052. Return Value:
  9053. RPC_S_OK or other RPC_S_* errors for error
  9054. --*/
  9055. {
  9056. // many channels don't support this and
  9057. // shouldn't be called with it. Those who do support it
  9058. // should override it.
  9059. ASSERT(FALSE);
  9060. return RPC_S_INTERNAL_ERROR;
  9061. }
  9062. RPC_STATUS HTTP2Channel::LastPacketSentNotification (
  9063. IN HTTP2SendContext *LastSendContext
  9064. )
  9065. /*++
  9066. Routine Description:
  9067. When a lower channel wants to notify the top
  9068. channel that the last packet has been sent,
  9069. they call this function. Must be called from
  9070. an upcall/neutral context. Only flow control
  9071. senders support past packet notifications
  9072. Arguments:
  9073. LastSendContext - the context we're sending
  9074. Return Value:
  9075. The value to return to the bottom channel/runtime.
  9076. --*/
  9077. {
  9078. ASSERT(0);
  9079. return RPC_S_INTERNAL_ERROR;
  9080. }
  9081. void HTTP2Channel::SendCancelled (
  9082. IN HTTP2SendContext *SendContext
  9083. )
  9084. /*++
  9085. Routine Description:
  9086. A lower channel cancelled a send already passed through this channel.
  9087. Arguments:
  9088. SendContext - the send context of the send that was cancelled
  9089. Return Value:
  9090. --*/
  9091. {
  9092. RemoveReference();
  9093. }
  9094. void HTTP2Channel::PingTrafficSentNotify (
  9095. IN ULONG PingTrafficSize
  9096. )
  9097. /*++
  9098. Routine Description:
  9099. Notifies a channel that ping traffic has been sent.
  9100. Arguments:
  9101. PingTrafficSize - the size of the ping traffic sent.
  9102. --*/
  9103. {
  9104. // nobody should be here. Channels that use that must
  9105. // override.
  9106. ASSERT(0);
  9107. }
  9108. void HTTP2Channel::FreeObject (
  9109. void
  9110. )
  9111. /*++
  9112. Routine Description:
  9113. Frees a client in channel object
  9114. Arguments:
  9115. Return Value:
  9116. --*/
  9117. {
  9118. // make sure we have been aborted
  9119. ASSERT(Aborted.GetInteger() > 0);
  9120. LowerLayer->FreeObject();
  9121. // the client channel is the top of the stack. Just free us
  9122. // which will free the whole stack
  9123. delete this;
  9124. }
  9125. RPC_STATUS HTTP2Channel::ForwardFlowControlAckOnDefaultChannel (
  9126. IN BOOL IsInChannel,
  9127. IN ForwardDestinations Destination,
  9128. IN ULONG BytesReceivedForAck,
  9129. IN ULONG WindowForAck
  9130. )
  9131. /*++
  9132. Routine Description:
  9133. Forwards a flow control ack on the default channel
  9134. Arguments:
  9135. IsInChannel - non-zero if the IN channel is to be used. FALSE
  9136. otherwise
  9137. Destination - where to forward to.
  9138. BytesReceivedForAck - the bytes received when the ACK was issued
  9139. WindowForAck - the free window when the ACK was issued.
  9140. Return Value:
  9141. RPC_S_OK or RPC_S_*
  9142. Notes:
  9143. If on an endpoint, called from a neutral context only. Proxies
  9144. call it in submission context.
  9145. --*/
  9146. {
  9147. HTTP2VirtualConnection *VirtualConnection;
  9148. HTTP2SendContext *SendContext;
  9149. RPC_STATUS RpcStatus;
  9150. VirtualConnection = LockParentPointer();
  9151. if (VirtualConnection == NULL)
  9152. return RPC_P_CONNECTION_SHUTDOWN;
  9153. // allocate and initalize the flow control ACK packet
  9154. SendContext = AllocateAndInitializeFlowControlAckPacketWithDestination (
  9155. Destination,
  9156. BytesReceivedForAck,
  9157. WindowForAck,
  9158. VirtualConnection->MapChannelIdToCookie(ChannelId)
  9159. );
  9160. if (SendContext == NULL)
  9161. {
  9162. UnlockParentPointer();
  9163. return RPC_S_OUT_OF_MEMORY;
  9164. }
  9165. RpcStatus = VirtualConnection->SendTrafficOnDefaultChannel(IsInChannel,
  9166. SendContext
  9167. );
  9168. UnlockParentPointer();
  9169. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  9170. FreeRTSPacket(SendContext);
  9171. return RpcStatus;
  9172. }
  9173. RPC_STATUS HTTP2Channel::ForwardFlowControlAckOnThisChannel (
  9174. IN ULONG BytesReceivedForAck,
  9175. IN ULONG WindowForAck,
  9176. IN BOOL NonChannelData
  9177. )
  9178. /*++
  9179. Routine Description:
  9180. Forwards a flow control ack on this channel
  9181. Arguments:
  9182. BytesReceivedForAck - the bytes received when the ACK was issued
  9183. WindowForAck - the free window when the ACK was issued.
  9184. NonChannelData - non-zero if the data being sent don't go on the HTTP
  9185. channel. FALSE if they do
  9186. Return Value:
  9187. RPC_S_OK or RPC_S_*
  9188. Notes:
  9189. This must be called in upcall or neutral context only
  9190. --*/
  9191. {
  9192. HTTP2SendContext *SendContext;
  9193. RPC_STATUS RpcStatus;
  9194. HTTP2VirtualConnection *VirtualConnection;
  9195. VirtualConnection = LockParentPointer();
  9196. if (VirtualConnection == NULL)
  9197. return RPC_P_CONNECTION_SHUTDOWN;
  9198. // allocate and initalize the flow control ACK packet
  9199. SendContext = AllocateAndInitializeFlowControlAckPacket (
  9200. BytesReceivedForAck,
  9201. WindowForAck,
  9202. VirtualConnection->MapChannelIdToCookie(ChannelId)
  9203. );
  9204. UnlockParentPointer();
  9205. if (SendContext == NULL)
  9206. return RPC_S_OUT_OF_MEMORY;
  9207. if (NonChannelData)
  9208. SendContext->Flags |= SendContextFlagNonChannelData;
  9209. RpcStatus = Send(SendContext);
  9210. // this can be called on the server, or on the proxy. If on the server,
  9211. // it will be called with NonChannelData. This means we cannot have
  9212. // channel recycle indication here.
  9213. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  9214. if (RpcStatus != RPC_S_OK)
  9215. {
  9216. FreeRTSPacket(SendContext);
  9217. }
  9218. return RpcStatus;
  9219. }
  9220. RPC_STATUS HTTP2Channel::HandleSendResultFromNeutralContext (
  9221. IN RPC_STATUS CurrentStatus
  9222. )
  9223. /*++
  9224. Routine Description:
  9225. Handles the result code from send from a neutral context.
  9226. This includes checking for channel recycling and intiating
  9227. one if necessary.
  9228. Arguments:
  9229. CurrentStatus - the status from the send operation
  9230. Return Value:
  9231. RPC_S_OK or RPC_S_*. Callers may ignore it since all cleanup was
  9232. done.
  9233. Notes:
  9234. This must be called in upcall or neutral context only
  9235. --*/
  9236. {
  9237. RPC_STATUS RpcStatus;
  9238. HTTP2VirtualConnection *VirtualConnection;
  9239. ASSERT(CurrentStatus != RPC_S_CANNOT_SUPPORT);
  9240. ASSERT(CurrentStatus != RPC_S_INTERNAL_ERROR);
  9241. if (CurrentStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  9242. {
  9243. // recycle the parent connection
  9244. VirtualConnection = LockParentPointer();
  9245. if (VirtualConnection)
  9246. {
  9247. RpcStatus = VirtualConnection->RecycleChannel(
  9248. TRUE // IsFromUpcall
  9249. );
  9250. UnlockParentPointer();
  9251. if (RpcStatus != RPC_S_OK)
  9252. {
  9253. // if this failed, abort the whole connection
  9254. AbortConnection(CurrentStatus);
  9255. }
  9256. CurrentStatus = RpcStatus;
  9257. }
  9258. else
  9259. {
  9260. // nothing to do - the channel is dying anyway
  9261. CurrentStatus = RPC_P_CONNECTION_SHUTDOWN;
  9262. }
  9263. }
  9264. return CurrentStatus;
  9265. }
  9266. RPC_STATUS HTTP2Channel::IsInChannel (
  9267. OUT BOOL *InChannel
  9268. )
  9269. /*++
  9270. Routine Description:
  9271. Checks if the current channel is an in channel or an
  9272. out channel.
  9273. Arguments:
  9274. InChannel - on output will be set to non-zero if this is an
  9275. in channel. It will be set to 0 if this is an out channel.
  9276. Undefined on failure.
  9277. Return Value:
  9278. RPC_S_OK or RPC_P_CONNECTION_SHUTDOWN. If the parent has detached,
  9279. RPC_P_CONNECTION_SHUTDOWN will be returned. In all other cases
  9280. success is returned.
  9281. --*/
  9282. {
  9283. HTTP2VirtualConnection *VirtualConnection;
  9284. VirtualConnection = LockParentPointer();
  9285. if (VirtualConnection)
  9286. {
  9287. VirtualConnection->VerifyValidChannelId(ChannelId);
  9288. *InChannel = VirtualConnection->IsInChannel(ChannelId);
  9289. UnlockParentPointer();
  9290. return RPC_S_OK;
  9291. }
  9292. else
  9293. return RPC_P_CONNECTION_SHUTDOWN;
  9294. }
  9295. /*********************************************************************
  9296. HTTP2VirtualConnection
  9297. *********************************************************************/
  9298. RPC_STATUS HTTP2VirtualConnection::Send (
  9299. IN UINT Length,
  9300. IN BUFFER Buffer,
  9301. IN PVOID SendContext
  9302. )
  9303. /*++
  9304. Routine Description:
  9305. Send on an HTTP client virtual connection. Proxies don't
  9306. override that. Other virtual connections may override it.
  9307. Arguments:
  9308. Length - The length of the data to send.
  9309. Buffer - The data to send.
  9310. SendContext - A buffer of at least SendContextSize bytes
  9311. which will be used during the call and returned
  9312. when the send completes.
  9313. Return Value:
  9314. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9315. Note:
  9316. Can be called from runtime/neutral context only.
  9317. --*/
  9318. {
  9319. HTTP2ChannelPointer *ChannelPtr;
  9320. HTTP2Channel *Channel;
  9321. HTTP2SendContext *HttpSendContext;
  9322. RPC_STATUS RpcStatus;
  9323. HttpSendContext = (HTTP2SendContext *)SendContext;
  9324. HttpSendContext->SetListEntryUnused();
  9325. HttpSendContext->maxWriteBuffer = Length;
  9326. HttpSendContext->pWriteBuffer = Buffer;
  9327. HttpSendContext->TrafficType = http2ttData;
  9328. HttpSendContext->u.SyncEvent = NULL;
  9329. HttpSendContext->Flags = 0;
  9330. HttpSendContext->UserData = 0;
  9331. Channel = LockDefaultSendChannel(&ChannelPtr);
  9332. if (Channel)
  9333. {
  9334. RpcStatus = Channel->Send(HttpSendContext);
  9335. ChannelPtr->UnlockChannelPointer();
  9336. }
  9337. else
  9338. {
  9339. RpcStatus = RPC_P_SEND_FAILED;
  9340. }
  9341. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  9342. FALSE // IsFromUpcall
  9343. );
  9344. if (RpcStatus != RPC_S_OK)
  9345. {
  9346. Abort();
  9347. // Note that send can't really fail with protocol error. When
  9348. // it happens it has simply picked the error with which
  9349. // the connection was aborted. This is as good as a failed send.
  9350. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  9351. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  9352. || (RpcStatus == RPC_P_RECEIVE_FAILED)
  9353. || (RpcStatus == RPC_S_PROTOCOL_ERROR) )
  9354. {
  9355. RpcStatus = RPC_P_SEND_FAILED;
  9356. }
  9357. }
  9358. VALIDATE(RpcStatus)
  9359. {
  9360. RPC_S_OK,
  9361. RPC_S_OUT_OF_MEMORY,
  9362. RPC_S_OUT_OF_RESOURCES,
  9363. RPC_P_SEND_FAILED
  9364. } END_VALIDATE;
  9365. return RpcStatus;
  9366. }
  9367. RPC_STATUS HTTP2VirtualConnection::Receive (
  9368. void
  9369. )
  9370. /*++
  9371. Routine Description:
  9372. Post a receive on a HTTP client virtual connection.
  9373. Arguments:
  9374. Return Value:
  9375. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9376. --*/
  9377. {
  9378. HTTP2ChannelPointer *ChannelPtr;
  9379. HTTP2Channel *Channel;
  9380. RPC_STATUS RpcStatus;
  9381. Channel = LockDefaultReceiveChannel(&ChannelPtr);
  9382. if (Channel)
  9383. {
  9384. RpcStatus = Channel->Receive(http2ttData);
  9385. ChannelPtr->UnlockChannelPointer();
  9386. }
  9387. else
  9388. {
  9389. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9390. }
  9391. if (RpcStatus != RPC_S_OK)
  9392. {
  9393. Abort();
  9394. }
  9395. return RpcStatus;
  9396. }
  9397. RPC_STATUS HTTP2VirtualConnection::SyncSend (
  9398. IN ULONG BufferLength,
  9399. IN BYTE *Buffer,
  9400. IN BOOL fDisableShutdownCheck,
  9401. IN BOOL fDisableCancelCheck,
  9402. IN ULONG Timeout
  9403. )
  9404. /*++
  9405. Routine Description:
  9406. Do a sync send on an HTTP connection.
  9407. Arguments:
  9408. BufferLength - the length of the data to send.
  9409. Buffer - the data to send.
  9410. fDisableShutdownCheck - ignored
  9411. fDisableCancelCheck - runtime indicates no cancel
  9412. will be attempted on this send. Can be used
  9413. as optimization hint by the transport
  9414. Timeout - send timeout (call timeout)
  9415. Return Value:
  9416. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9417. --*/
  9418. {
  9419. RPC_STATUS RpcStatus;
  9420. RPC_STATUS RpcStatus2;
  9421. HTTP2SendContext LocalSendContext;
  9422. HTTP2Channel *Channel;
  9423. HTTP2ChannelPointer *ChannelPtr;
  9424. // we will convert a sync send to an async send
  9425. // make sure there is a thread to pick up the completion
  9426. RpcStatus = HTTPTransInfo->CreateThread();
  9427. if (RpcStatus != RPC_S_OK)
  9428. {
  9429. if (RpcStatus == RPC_S_OUT_OF_THREADS)
  9430. RpcStatus = RPC_S_OUT_OF_RESOURCES;
  9431. VALIDATE(RpcStatus)
  9432. {
  9433. RPC_S_OK,
  9434. RPC_S_OUT_OF_MEMORY,
  9435. RPC_S_OUT_OF_RESOURCES,
  9436. RPC_P_SEND_FAILED,
  9437. RPC_S_CALL_CANCELLED,
  9438. RPC_P_RECEIVE_COMPLETE,
  9439. RPC_P_TIMEOUT
  9440. } END_VALIDATE;
  9441. return RpcStatus;
  9442. }
  9443. Channel = LockDefaultSendChannel (&ChannelPtr);
  9444. if (Channel == NULL)
  9445. {
  9446. return RPC_P_SEND_FAILED;
  9447. }
  9448. RpcStatus = Channel->SyncSend(http2ttData,
  9449. BufferLength,
  9450. Buffer,
  9451. fDisableCancelCheck,
  9452. Timeout,
  9453. this,
  9454. &LocalSendContext
  9455. );
  9456. ChannelPtr->UnlockChannelPointer();
  9457. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  9458. {
  9459. // get the ball rolling with the recycle
  9460. RpcStatus = RecycleChannel(
  9461. FALSE // IsFromUpcall
  9462. );
  9463. // ok or not, we have to wait for IO to complete
  9464. RpcStatus2 = WaitForSyncSend(this,
  9465. &LocalSendContext,
  9466. this,
  9467. fDisableCancelCheck,
  9468. Timeout
  9469. );
  9470. if ((RpcStatus2 == RPC_S_OK) && (RpcStatus != RPC_S_OK))
  9471. RpcStatus2 = RpcStatus;
  9472. if ((RpcStatus2 == RPC_P_CONNECTION_SHUTDOWN)
  9473. || (RpcStatus2 == RPC_P_RECEIVE_FAILED)
  9474. || (RpcStatus2 == RPC_P_CONNECTION_CLOSED)
  9475. || (RpcStatus2 == RPC_S_SERVER_UNAVAILABLE)
  9476. || (RpcStatus2 == RPC_S_PROTOCOL_ERROR) )
  9477. RpcStatus2 = RPC_P_SEND_FAILED;
  9478. VALIDATE(RpcStatus2)
  9479. {
  9480. RPC_S_OK,
  9481. RPC_S_OUT_OF_MEMORY,
  9482. RPC_S_OUT_OF_RESOURCES,
  9483. RPC_P_SEND_FAILED,
  9484. RPC_S_CALL_CANCELLED,
  9485. RPC_P_RECEIVE_COMPLETE,
  9486. RPC_P_TIMEOUT,
  9487. }
  9488. END_VALIDATE;
  9489. return RpcStatus2;
  9490. }
  9491. else
  9492. {
  9493. if (RpcStatus == RPC_S_OK)
  9494. {
  9495. RpcStatus = WaitForSyncSend(this,
  9496. &LocalSendContext,
  9497. this,
  9498. fDisableCancelCheck,
  9499. Timeout
  9500. );
  9501. }
  9502. if (RpcStatus != RPC_S_OK)
  9503. {
  9504. if ((RpcStatus == RPC_P_RECEIVE_FAILED)
  9505. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  9506. || (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  9507. || (RpcStatus == RPC_S_SERVER_UNAVAILABLE)
  9508. || (RpcStatus == RPC_S_PROTOCOL_ERROR) )
  9509. RpcStatus = RPC_P_SEND_FAILED;
  9510. }
  9511. VALIDATE(RpcStatus)
  9512. {
  9513. RPC_S_OK,
  9514. RPC_S_OUT_OF_MEMORY,
  9515. RPC_S_OUT_OF_RESOURCES,
  9516. RPC_P_SEND_FAILED,
  9517. RPC_S_CALL_CANCELLED,
  9518. RPC_P_RECEIVE_COMPLETE,
  9519. RPC_P_TIMEOUT,
  9520. RPC_S_SERVER_UNAVAILABLE
  9521. }
  9522. END_VALIDATE;
  9523. return RpcStatus;
  9524. }
  9525. }
  9526. RPC_STATUS HTTP2VirtualConnection::SyncRecv (
  9527. IN BYTE **Buffer,
  9528. IN ULONG *BufferLength,
  9529. IN ULONG Timeout
  9530. )
  9531. /*++
  9532. Routine Description:
  9533. Do a sync receive on an HTTP connection.
  9534. Arguments:
  9535. Buffer - if successful, points to a buffer containing the next PDU.
  9536. BufferLength - if successful, contains the length of the message.
  9537. Timeout - the amount of time to wait for the receive. If -1, we wait
  9538. infinitely.
  9539. Return Value:
  9540. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  9541. --*/
  9542. {
  9543. // nobody should be calling SyncRecv on the base connection
  9544. ASSERT(0);
  9545. return RPC_S_INTERNAL_ERROR;
  9546. }
  9547. void HTTP2VirtualConnection::Close (
  9548. IN BOOL DontFlush
  9549. )
  9550. /*++
  9551. Routine Description:
  9552. Closes an HTTP connection. Proxies don't
  9553. override that. Other virtual connections may override it.
  9554. Arguments:
  9555. DontFlush - non-zero if all buffers need to be flushed
  9556. before closing the connection. Zero otherwise.
  9557. Return Value:
  9558. --*/
  9559. {
  9560. Abort();
  9561. }
  9562. RPC_STATUS HTTP2VirtualConnection::TurnOnOffKeepAlives (
  9563. IN BOOL TurnOn,
  9564. IN BOOL bProtectIO,
  9565. IN BOOL IsFromUpcall,
  9566. IN KEEPALIVE_TIMEOUT_UNITS Units,
  9567. IN OUT KEEPALIVE_TIMEOUT KATime,
  9568. IN ULONG KAInterval OPTIONAL
  9569. )
  9570. /*++
  9571. Routine Description:
  9572. Turns on keep alives for HTTP. Proxies don't
  9573. override that. Other virtual connections may override it.
  9574. Arguments:
  9575. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  9576. are turned off.
  9577. bProtectIO - non-zero if IO needs to be protected against async close
  9578. of the connection.
  9579. IsFromUpcall - non-zero if called from upcall context. Zero otherwise.
  9580. Units - in what units is KATime
  9581. KATime - how much to wait before turning on keep alives
  9582. KAInterval - the interval between keep alives
  9583. Return Value:
  9584. RPC_S_OK or RPC_S_* / Win32 errors on failure
  9585. Note:
  9586. If we use it on the server, we must protect
  9587. the connection against async aborts.
  9588. --*/
  9589. {
  9590. // The server doesn't support this for Whistler. Think
  9591. // about it for Longhorn. Client overrides it.
  9592. ASSERT(FALSE);
  9593. return RPC_S_INTERNAL_ERROR;
  9594. }
  9595. RPC_STATUS HTTP2VirtualConnection::QueryClientAddress (
  9596. OUT RPC_CHAR **pNetworkAddress
  9597. )
  9598. /*++
  9599. Routine Description:
  9600. Returns the IP address of the client on a connection as a string.
  9601. This is a server side function. Assert on the client. Proxies don't
  9602. override that. Other virtual connections may override it.
  9603. Arguments:
  9604. NetworkAddress - Will contain string on success.
  9605. Return Value:
  9606. RPC_S_OK or other RPC_S_* errors for error
  9607. --*/
  9608. {
  9609. ASSERT(FALSE);
  9610. return RPC_S_INTERNAL_ERROR;
  9611. }
  9612. RPC_STATUS HTTP2VirtualConnection::QueryLocalAddress (
  9613. IN OUT void *Buffer,
  9614. IN OUT unsigned long *BufferSize,
  9615. OUT unsigned long *AddressFormat
  9616. )
  9617. /*++
  9618. Routine Description:
  9619. Returns the local IP address of a connection.
  9620. This is a server side function. Assert on the client. Proxies don't
  9621. override that. Other virtual connections may override it.
  9622. Arguments:
  9623. Buffer - The buffer that will receive the output address
  9624. BufferSize - the size of the supplied Buffer on input. On output the
  9625. number of bytes written to the buffer. If the buffer is too small
  9626. to receive all the output data, ERROR_MORE_DATA is returned,
  9627. nothing is written to the buffer, and BufferSize is set to
  9628. the size of the buffer needed to return all the data.
  9629. AddressFormat - a constant indicating the format of the returned address.
  9630. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  9631. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  9632. Return Value:
  9633. RPC_S_OK or other RPC_S_* errors for error
  9634. --*/
  9635. {
  9636. ASSERT(FALSE);
  9637. return RPC_S_INTERNAL_ERROR;
  9638. }
  9639. RPC_STATUS HTTP2VirtualConnection::QueryClientId(
  9640. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  9641. )
  9642. /*++
  9643. Routine Description:
  9644. For secure protocols (which TCP/IP is not) this is supposed to
  9645. give an ID which will be shared by all clients from the same
  9646. process. This prevents one user from grabbing another users
  9647. association group and using their context handles.
  9648. Since TCP/IP is not secure we return the IP address of the
  9649. client machine. This limits the attacks to other processes
  9650. running on the client machine which is better than nothing.
  9651. This is a server side function. Assert on the client. Proxies don't
  9652. override that. Other virtual connections may override it.
  9653. Arguments:
  9654. ClientProcess - Transport identification of the "client".
  9655. Return Value:
  9656. RPC_S_OK or other RPC_S_* errors for error
  9657. --*/
  9658. {
  9659. ASSERT(0);
  9660. return RPC_S_INTERNAL_ERROR;
  9661. }
  9662. RPC_STATUS HTTP2VirtualConnection::QueryClientIpAddress (
  9663. IN OUT RPC_CLIENT_IP_ADDRESS *ClientIpAddress
  9664. )
  9665. /*++
  9666. Routine Description:
  9667. Returns the IP address of the client on a connection.
  9668. This is a server side function. Assert on the client. Proxies don't
  9669. override that. Other virtual connections may override it.
  9670. Arguments:
  9671. ClientIpAddress - Will contain the ip address on success.
  9672. Return Value:
  9673. RPC_S_OK or other RPC_S_* errors for error
  9674. --*/
  9675. {
  9676. ASSERT(FALSE);
  9677. return RPC_S_INTERNAL_ERROR;
  9678. }
  9679. void HTTP2VirtualConnection::AbortChannels (
  9680. IN RPC_STATUS RpcStatus
  9681. )
  9682. /*++
  9683. Routine Description:
  9684. Aborts an HTTP connection but does not disconnect
  9685. the channels. Can be called from above, upcall, or
  9686. neutral context, but not from submit context!
  9687. Arguments:
  9688. RpcStatus - the error to abort the channels with
  9689. Return Value:
  9690. --*/
  9691. {
  9692. HTTP2ChannelPointer *Channels[4];
  9693. HTTP2Channel *CurrentChannel;
  9694. int i;
  9695. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  9696. // quick optimization. Don't abort already aborted channels
  9697. // All channels are protected against double abortion - this
  9698. // is just an optimization
  9699. if (Aborted.GetInteger() > 0)
  9700. return;
  9701. Channels[0] = &InChannels[0];
  9702. Channels[1] = &InChannels[1];
  9703. Channels[2] = &OutChannels[0];
  9704. Channels[3] = &OutChannels[1];
  9705. for (i = 0; i < 4; i ++)
  9706. {
  9707. CurrentChannel = Channels[i]->LockChannelPointer();
  9708. if (CurrentChannel)
  9709. {
  9710. CurrentChannel->Abort(RpcStatus);
  9711. Channels[i]->UnlockChannelPointer();
  9712. }
  9713. }
  9714. }
  9715. BOOL HTTP2VirtualConnection::AbortAndDestroy (
  9716. IN BOOL IsFromChannel,
  9717. IN int CallingChannelId,
  9718. IN RPC_STATUS AbortStatus
  9719. )
  9720. /*++
  9721. Routine Description:
  9722. Aborts and destroys a connection. This is safe to
  9723. call from an upcall, as long as the calling channel
  9724. passes in its channel id. Actually the destruction
  9725. does not happen here. The caller has the obligation
  9726. to destroy it after synchronizing its upcalls.
  9727. Arguments:
  9728. IsFromChannel - non-zero if the call comes from a channel.
  9729. Zero otherwise.
  9730. CallingChannelId - the id of the calling channel. If IsFromChannel
  9731. is FALSE, this argument should be ignored.
  9732. AbortStatus - the error to abort the connection with.
  9733. Return Value:
  9734. non-zero - caller may destroy the connection.
  9735. FALSE - destruction is already in progress. Caller
  9736. must not destroy the connection.
  9737. --*/
  9738. {
  9739. if (IsFromChannel)
  9740. {
  9741. VerifyValidChannelId(CallingChannelId);
  9742. }
  9743. // abort the channels themselves
  9744. AbortChannels(AbortStatus);
  9745. // we got to the destructive phase of the abort
  9746. // guard against double aborts
  9747. if (Aborted.Increment() > 1)
  9748. return FALSE;
  9749. DisconnectChannels(IsFromChannel, CallingChannelId);
  9750. // we have disconnected all but the channel on which we received
  9751. // this call.
  9752. return TRUE;
  9753. }
  9754. void HTTP2VirtualConnection::LastPacketSentNotification (
  9755. IN int ChannelId,
  9756. IN HTTP2SendContext *LastSendContext
  9757. )
  9758. /*++
  9759. Routine Description:
  9760. When a channel wants to notify the virtual connection
  9761. that the last packet has been sent, they call this function.
  9762. Must be called from an upcall/neutral context. Only flow control
  9763. senders generated past packet notifications
  9764. Arguments:
  9765. ChannelId - the channelfor which this notification is.
  9766. LastSendContext - the send context for the last send
  9767. Return Value:
  9768. --*/
  9769. {
  9770. ASSERT(0);
  9771. }
  9772. RPC_STATUS HTTP2VirtualConnection::PostReceiveOnChannel (
  9773. IN HTTP2ChannelPointer *ChannelPtr,
  9774. IN HTTP2TrafficType TrafficType
  9775. )
  9776. /*++
  9777. Routine Description:
  9778. Posts a receceive on specified channel
  9779. Arguments:
  9780. ChannelPtr - the channel pointer to post the receive on
  9781. TrafficType - the type of traffic we wish to receive
  9782. Return Value:
  9783. RPC_S_OK or RPC_S_* error
  9784. --*/
  9785. {
  9786. HTTP2Channel *Channel;
  9787. RPC_STATUS RpcStatus;
  9788. if (ChannelPtr == NULL)
  9789. {
  9790. // This should never happen.
  9791. ASSERT(0);
  9792. return RPC_S_INTERNAL_ERROR;
  9793. }
  9794. Channel = ChannelPtr->LockChannelPointer();
  9795. if (Channel)
  9796. {
  9797. RpcStatus = Channel->Receive(TrafficType);
  9798. ChannelPtr->UnlockChannelPointer();
  9799. }
  9800. else
  9801. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9802. return RpcStatus;
  9803. }
  9804. RPC_STATUS HTTP2VirtualConnection::PostReceiveOnDefaultChannel (
  9805. IN BOOL IsInChannel,
  9806. IN HTTP2TrafficType TrafficType
  9807. )
  9808. /*++
  9809. Routine Description:
  9810. Posts a receceive on the default channel for the specified type
  9811. Arguments:
  9812. IsInChannel - if non-zero, post a receive on default in channel.
  9813. If 0, post a receive on default out channel
  9814. TrafficType - the type of traffic we wish to receive
  9815. Return Value:
  9816. RPC_S_OK or RPC_S_* error
  9817. --*/
  9818. {
  9819. HTTP2Channel *Channel;
  9820. HTTP2ChannelPointer *ChannelPtr;
  9821. RPC_STATUS RpcStatus;
  9822. if (IsInChannel)
  9823. Channel = LockDefaultInChannel(&ChannelPtr);
  9824. else
  9825. Channel = LockDefaultOutChannel(&ChannelPtr);
  9826. if (Channel)
  9827. {
  9828. RpcStatus = Channel->Receive(TrafficType);
  9829. ChannelPtr->UnlockChannelPointer();
  9830. }
  9831. else
  9832. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9833. return RpcStatus;
  9834. }
  9835. RPC_STATUS HTTP2VirtualConnection::ForwardTrafficToChannel (
  9836. IN HTTP2ChannelPointer *ChannelPtr,
  9837. IN BYTE *Packet,
  9838. IN ULONG PacketLength
  9839. )
  9840. /*++
  9841. Routine Description:
  9842. Forwards the given packet on the given channel
  9843. Arguments:
  9844. ChannelPtr - the channel pointer
  9845. Packet - the packet to forward
  9846. PacketLength - the length of the packet to forward
  9847. Return Value:
  9848. RPC_S_OK or RPC_S_* error
  9849. --*/
  9850. {
  9851. HTTP2Channel *Channel;
  9852. RPC_STATUS RpcStatus;
  9853. Channel = ChannelPtr->LockChannelPointer();
  9854. if (Channel)
  9855. {
  9856. RpcStatus = Channel->ForwardTraffic(Packet, PacketLength);
  9857. ChannelPtr->UnlockChannelPointer();
  9858. }
  9859. else
  9860. {
  9861. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9862. }
  9863. return RpcStatus;
  9864. }
  9865. RPC_STATUS HTTP2VirtualConnection::ForwardTrafficToDefaultChannel (
  9866. IN BOOL IsInChannel,
  9867. IN BYTE *Packet,
  9868. IN ULONG PacketLength
  9869. )
  9870. /*++
  9871. Routine Description:
  9872. Forwards the given packet on the given channel
  9873. Arguments:
  9874. IsInChannel - if non-zero, forward to default in channel.
  9875. If 0, forward to default out channel
  9876. Packet - the packet to forward
  9877. PacketLength - the length of the packet to forward
  9878. Return Value:
  9879. RPC_S_OK or RPC_S_* error
  9880. --*/
  9881. {
  9882. HTTP2Channel *Channel;
  9883. HTTP2ChannelPointer *ChannelPtr;
  9884. RPC_STATUS RpcStatus;
  9885. if (IsInChannel)
  9886. Channel = LockDefaultInChannel(&ChannelPtr);
  9887. else
  9888. Channel = LockDefaultOutChannel(&ChannelPtr);
  9889. if (Channel)
  9890. {
  9891. RpcStatus = Channel->ForwardTraffic(Packet, PacketLength);
  9892. ChannelPtr->UnlockChannelPointer();
  9893. }
  9894. else
  9895. {
  9896. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9897. }
  9898. return RpcStatus;
  9899. }
  9900. RPC_STATUS HTTP2VirtualConnection::SendTrafficOnChannel (
  9901. IN HTTP2ChannelPointer *ChannelPtr,
  9902. IN HTTP2SendContext *SendContext
  9903. )
  9904. /*++
  9905. Routine Description:
  9906. Sends the given packet on the given channel
  9907. Arguments:
  9908. ChannelPtr - the channel pointer on which to send.
  9909. SendContext - context to send
  9910. Return Value:
  9911. RPC_S_OK or RPC_S_* error
  9912. --*/
  9913. {
  9914. HTTP2Channel *Channel;
  9915. RPC_STATUS RpcStatus;
  9916. Channel = ChannelPtr->LockChannelPointer();
  9917. if (Channel)
  9918. {
  9919. RpcStatus = Channel->Send(SendContext);
  9920. ChannelPtr->UnlockChannelPointer();
  9921. }
  9922. else
  9923. {
  9924. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9925. }
  9926. return RpcStatus;
  9927. }
  9928. RPC_STATUS HTTP2VirtualConnection::SendTrafficOnDefaultChannel (
  9929. IN BOOL IsInChannel,
  9930. IN HTTP2SendContext *SendContext
  9931. )
  9932. /*++
  9933. Routine Description:
  9934. Sends the given packet on the given channel
  9935. Arguments:
  9936. IsInChannel - if non-zero, send on default in channel.
  9937. If 0, send on default out channel
  9938. SendContext - context to send
  9939. Return Value:
  9940. RPC_S_OK or RPC_S_* error
  9941. --*/
  9942. {
  9943. HTTP2Channel *Channel;
  9944. HTTP2ChannelPointer *ChannelPtr;
  9945. RPC_STATUS RpcStatus;
  9946. if (IsInChannel)
  9947. Channel = LockDefaultInChannel(&ChannelPtr);
  9948. else
  9949. Channel = LockDefaultOutChannel(&ChannelPtr);
  9950. if (Channel)
  9951. {
  9952. RpcStatus = Channel->Send(SendContext);
  9953. ChannelPtr->UnlockChannelPointer();
  9954. }
  9955. else
  9956. {
  9957. RpcStatus = RPC_P_CONNECTION_CLOSED;
  9958. }
  9959. return RpcStatus;
  9960. }
  9961. RPC_STATUS HTTP2VirtualConnection::RecycleChannel (
  9962. IN BOOL IsFromUpcall
  9963. )
  9964. /*++
  9965. Routine Description:
  9966. Initiates channel recycling. Each endpoint supports
  9967. initiating recycling of only one channel, so it knows
  9968. which one it is.
  9969. Endpoints override that. On proxies it shouldn't be called
  9970. at all.
  9971. Arguments:
  9972. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  9973. Return Value:
  9974. RPC_S_OK of the recycling operation started successfully.
  9975. RPC_S_* error for errors.
  9976. --*/
  9977. {
  9978. ASSERT(0);
  9979. return RPC_S_INTERNAL_ERROR;
  9980. }
  9981. RPC_STATUS HTTP2VirtualConnection::StartChannelRecyclingIfNecessary (
  9982. IN RPC_STATUS RpcStatus,
  9983. IN BOOL IsFromUpcall
  9984. )
  9985. /*++
  9986. Routine Description:
  9987. Checks the result of the send for channel recycle indication, and if one
  9988. is present, initiate channel recycle
  9989. Arguments:
  9990. RpcStatus - the return code from the Send operation.
  9991. IsFromUpcall - non-zero if this was called from an upcall. Zero otherwise.
  9992. Return Value:
  9993. RPC_S_* errors - the channel recycling failed to start.
  9994. any success code will be the passed in success code turned around.
  9995. If this function starts with a failure, the failure will be turned around
  9996. Notes:
  9997. May be called in an upcall or runtime context only.
  9998. --*/
  9999. {
  10000. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  10001. RpcStatus = RecycleChannel(IsFromUpcall);
  10002. return RpcStatus;
  10003. }
  10004. HTTP2Channel *HTTP2VirtualConnection::MapCookieToChannelPointer (
  10005. IN HTTP2Cookie *ChannelCookie,
  10006. OUT HTTP2ChannelPointer **ChannelPtr
  10007. )
  10008. /*++
  10009. Routine Description:
  10010. Maps a channel cookie to a channel pointer. A channel will be selected only if
  10011. it is the default channel as well. The returned channel is locked.
  10012. Arguments:
  10013. ChannelCookie - the cookie for the channel.
  10014. ChannelPtr - the channel pointer. On NULL return value this is undefined.
  10015. Return Value:
  10016. The channel if the channel was found or NULL
  10017. if the channel was not found. During some recycling scenarios
  10018. the channel may not be there, or the returning channel pointer
  10019. may have a detached channel
  10020. --*/
  10021. {
  10022. volatile int *DefaultChannelSelector;
  10023. int TargetChannelSelector;
  10024. HTTP2ChannelPointer *LocalChannelPtr;
  10025. HTTP2Channel *Channel;
  10026. if (InChannelCookies[0].Compare(ChannelCookie) == 0)
  10027. {
  10028. LocalChannelPtr = &InChannels[0];
  10029. DefaultChannelSelector = &DefaultInChannelSelector;
  10030. TargetChannelSelector = 0;
  10031. }
  10032. else if (InChannelCookies[1].Compare(ChannelCookie) == 0)
  10033. {
  10034. LocalChannelPtr = &InChannels[1];
  10035. DefaultChannelSelector = &DefaultInChannelSelector;
  10036. TargetChannelSelector = 1;
  10037. }
  10038. else if (OutChannelCookies[0].Compare(ChannelCookie) == 0)
  10039. {
  10040. LocalChannelPtr = &OutChannels[0];
  10041. DefaultChannelSelector = &DefaultOutChannelSelector;
  10042. TargetChannelSelector = 0;
  10043. }
  10044. else if (OutChannelCookies[1].Compare(ChannelCookie) == 0)
  10045. {
  10046. LocalChannelPtr = &OutChannels[1];
  10047. DefaultChannelSelector = &DefaultOutChannelSelector;
  10048. TargetChannelSelector = 1;
  10049. }
  10050. else
  10051. return NULL;
  10052. Channel = LocalChannelPtr->LockChannelPointer();
  10053. if (Channel)
  10054. {
  10055. if (*DefaultChannelSelector == TargetChannelSelector)
  10056. {
  10057. // if we locked the channel and it is the right channel,
  10058. // use it
  10059. *ChannelPtr = LocalChannelPtr;
  10060. return Channel;
  10061. }
  10062. LocalChannelPtr->UnlockChannelPointer();
  10063. }
  10064. return NULL;
  10065. }
  10066. HTTP2Channel *HTTP2VirtualConnection::MapCookieToAnyChannelPointer (
  10067. IN HTTP2Cookie *ChannelCookie,
  10068. OUT HTTP2ChannelPointer **ChannelPtr
  10069. )
  10070. /*++
  10071. Routine Description:
  10072. Maps a channel cookie to a channel pointer. Unlike MapCookieToChannelPointer,
  10073. channel will be selected regardless of whether it is default.The returned
  10074. channel is locked.
  10075. Arguments:
  10076. ChannelCookie - the cookie for the channel.
  10077. ChannelPtr - the channel pointer. On NULL return value this is undefined.
  10078. Return Value:
  10079. The channel if the channel was found or NULL
  10080. if the channel was not found. During some recycling scenarios
  10081. the channel may not be there, or the returning channel pointer
  10082. may have a detached channel
  10083. --*/
  10084. {
  10085. HTTP2ChannelPointer *LocalChannelPtr;
  10086. HTTP2Channel *Channel;
  10087. if (InChannelCookies[0].Compare(ChannelCookie) == 0)
  10088. {
  10089. LocalChannelPtr = &InChannels[0];
  10090. }
  10091. else if (InChannelCookies[1].Compare(ChannelCookie) == 0)
  10092. {
  10093. LocalChannelPtr = &InChannels[1];
  10094. }
  10095. else if (OutChannelCookies[0].Compare(ChannelCookie) == 0)
  10096. {
  10097. LocalChannelPtr = &OutChannels[0];
  10098. }
  10099. else if (OutChannelCookies[1].Compare(ChannelCookie) == 0)
  10100. {
  10101. LocalChannelPtr = &OutChannels[1];
  10102. }
  10103. else
  10104. return NULL;
  10105. Channel = LocalChannelPtr->LockChannelPointer();
  10106. if (Channel)
  10107. {
  10108. // if we locked the channel and it is the right channel,
  10109. // use it
  10110. *ChannelPtr = LocalChannelPtr;
  10111. return Channel;
  10112. }
  10113. return NULL;
  10114. }
  10115. HTTP2Channel *HTTP2VirtualConnection::LockDefaultSendChannel (
  10116. OUT HTTP2ChannelPointer **ChannelPtr
  10117. )
  10118. /*++
  10119. Routine Description:
  10120. Locks the send channel. Most connections don't override that.
  10121. Arguments:
  10122. ChannelPtr - on success, the channel pointer to use.
  10123. Return Value:
  10124. The locked channel or NULL (same semantics as LockDefaultOutChannel)
  10125. --*/
  10126. {
  10127. return LockDefaultOutChannel(ChannelPtr);
  10128. }
  10129. HTTP2Channel *HTTP2VirtualConnection::LockDefaultReceiveChannel (
  10130. OUT HTTP2ChannelPointer **ChannelPtr
  10131. )
  10132. /*++
  10133. Routine Description:
  10134. Locks the receive channel. Most connections don't override that.
  10135. Arguments:
  10136. ChannelPtr - on success, the channel pointer to use.
  10137. Return Value:
  10138. The locked channel or NULL (same semantics as LockDefaultInChannel)
  10139. --*/
  10140. {
  10141. return LockDefaultInChannel(ChannelPtr);
  10142. }
  10143. void HTTP2VirtualConnection::SetFirstInChannel (
  10144. IN HTTP2Channel *NewChannel
  10145. )
  10146. /*++
  10147. Routine Description:
  10148. Sets the passed in channel as first default in channel.
  10149. Typically used during building a stack.
  10150. Arguments:
  10151. NewChannel - new in channel.
  10152. Return Value:
  10153. --*/
  10154. {
  10155. int InChannelId;
  10156. InChannelId = AllocateChannelId();
  10157. DefaultInChannelSelector = 0;
  10158. NewChannel->SetChannelId(InChannelId);
  10159. InChannels[0].SetChannel(NewChannel);
  10160. InChannelIds[0] = InChannelId;
  10161. }
  10162. void HTTP2VirtualConnection::SetFirstOutChannel (
  10163. IN HTTP2Channel *NewChannel
  10164. )
  10165. /*++
  10166. Routine Description:
  10167. Sets the passed in channel as first default out channel.
  10168. Typically used during building a stack.
  10169. Arguments:
  10170. NewChannel - new out channel.
  10171. Return Value:
  10172. --*/
  10173. {
  10174. int OutChannelId;
  10175. OutChannelId = AllocateChannelId();
  10176. DefaultOutChannelSelector = 0;
  10177. NewChannel->SetChannelId(OutChannelId);
  10178. OutChannels[0].SetChannel(NewChannel);
  10179. OutChannelIds[0] = OutChannelId;
  10180. }
  10181. void HTTP2VirtualConnection::SetNonDefaultInChannel (
  10182. IN HTTP2Channel *NewChannel
  10183. )
  10184. /*++
  10185. Routine Description:
  10186. Sets the non default in channel. Used during channel
  10187. recycling. Note that this MUST be called by the code
  10188. that received RPC_P_CHANNEL_NEEDS_RECYCLING, because
  10189. it is not thread safe.
  10190. Arguments:
  10191. NewChannel - new in channel.
  10192. Return Value:
  10193. --*/
  10194. {
  10195. int InChannelId;
  10196. int NonDefaultInChannelSelector;
  10197. InChannelId = AllocateChannelId();
  10198. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  10199. NewChannel->SetChannelId(InChannelId);
  10200. InChannels[NonDefaultInChannelSelector].SetChannel(NewChannel);
  10201. InChannelIds[NonDefaultInChannelSelector] = InChannelId;
  10202. }
  10203. void HTTP2VirtualConnection::SetNonDefaultOutChannel (
  10204. IN HTTP2Channel *NewChannel
  10205. )
  10206. /*++
  10207. Routine Description:
  10208. Sets the non default out channel. Used during channel
  10209. recycling. Note that this MUST be called by the code
  10210. that received RPC_P_CHANNEL_NEEDS_RECYCLING, because
  10211. it is not thread safe.
  10212. Arguments:
  10213. NewChannel - new out channel.
  10214. Return Value:
  10215. --*/
  10216. {
  10217. int OutChannelId;
  10218. int NonDefaultOutChannelSelector;
  10219. OutChannelId = AllocateChannelId();
  10220. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  10221. NewChannel->SetChannelId(OutChannelId);
  10222. OutChannels[NonDefaultOutChannelSelector].SetChannel(NewChannel);
  10223. OutChannelIds[NonDefaultOutChannelSelector] = OutChannelId;
  10224. }
  10225. void HTTP2VirtualConnection::DisconnectChannels (
  10226. IN BOOL ExemptChannel,
  10227. IN int ExemptChannelId
  10228. )
  10229. /*++
  10230. Routine Description:
  10231. Disconnects all channels. Must be called from runtime
  10232. or neutral context. Cannot be called from upcall or
  10233. submit context unless an exempt channel is given
  10234. Note that call must synchronize to ensure we're the only
  10235. thread doing the disconnect
  10236. Arguments:
  10237. ExemptChannel - non-zero if ExemptChannelId contains a
  10238. valid exempt channel id. FALSE otherwise.
  10239. ExemptChannelId - if ExemptChannel is non-zero, this argument
  10240. is the id of a channel that will be disconnected, but not
  10241. synchronized with up calls.
  10242. If ExampleChannel is FALSE, this argument is undefined
  10243. Return Value:
  10244. --*/
  10245. {
  10246. HTTP2ChannelPointer *Channels[4];
  10247. int ChannelIds[4];
  10248. HTTP2Channel *CurrentChannel;
  10249. int i;
  10250. // we should be the only thread aborting - just disconnect everybody
  10251. Channels[0] = &InChannels[0];
  10252. ChannelIds[0] = InChannelIds[0];
  10253. Channels[1] = &InChannels[1];
  10254. ChannelIds[1] = InChannelIds[1];
  10255. Channels[2] = &OutChannels[0];
  10256. ChannelIds[2] = OutChannelIds[0];
  10257. Channels[3] = &OutChannels[1];
  10258. ChannelIds[3] = OutChannelIds[1];
  10259. for (i = 0; i < 4; i ++)
  10260. {
  10261. if ((ExemptChannel == FALSE)
  10262. || ((ExemptChannel != FALSE) && (ExemptChannelId != ChannelIds[i])))
  10263. {
  10264. // disconnect the channel
  10265. Channels[i]->FreeChannelPointer(TRUE,
  10266. FALSE, // CalledFromUpcallContext
  10267. FALSE, // Abort
  10268. RPC_S_OK
  10269. );
  10270. }
  10271. else
  10272. {
  10273. Channels[i]->FreeChannelPointer(FALSE,
  10274. FALSE, // CalledFromUpcallContext
  10275. FALSE, // Abort
  10276. RPC_S_OK
  10277. );
  10278. }
  10279. }
  10280. }
  10281. /*********************************************************************
  10282. HTTP2ClientChannel
  10283. *********************************************************************/
  10284. const char *HeaderFragment1 = " http://";
  10285. const int HeaderFragment1Length = 8; // length of " http://"
  10286. const char *HeaderFragment2 = "/rpc/rpcproxy.dll?";
  10287. const int HeaderFragment2Length = 18; // length of /rpc/rpcproxy.dll?
  10288. const RPC_CHAR *HeaderFragment2W = L"/rpc/rpcproxy.dll?";
  10289. const int HeaderFragment2WLength = 36; // length of wide /rpc/rpcproxy.dll?
  10290. const char *HeaderFragment3 = ":";
  10291. const int HeaderFragment3Length = 1; // length of :
  10292. const RPC_CHAR *HeaderFragment3W = L":";
  10293. const int HeaderFragment3WLength = 2; // length of wide :
  10294. const char *HeaderFragment4 = " HTTP/1.1\r\nAccept:application/rpc\r\nUser-Agent:MSRPC\r\nHost:";
  10295. const int HeaderFragment4Length = 58; // length of " HTTP/1.1\r\nAccept:application/rpc\r\nUser-Agent:MSRPC\r\nHost:"
  10296. const char *HeaderFragment5 = "\r\nContent-Length:";
  10297. const int HeaderFragment5Length = 17; // "\r\nlength of Content-Length:"
  10298. const char *HeaderFragment6 = "\r\nConnection: Keep-Alive\r\nCache-control:no-cache\r\nPragma:no-cache\r\n\r\n";
  10299. const int HeaderFragment6Length = 69; // length of \r\nConnection: Keep-Alive\r\nCache-control:no-cache\r\nPragma:no-cache\r\n\r\n
  10300. const RPC_CHAR *HeaderAcceptType = L"application/rpc";
  10301. RPC_STATUS HTTP2ClientChannel::ClientOpen (
  10302. IN HTTPResolverHint *Hint,
  10303. IN const char *Verb,
  10304. IN int VerbLength,
  10305. IN BOOL InChannel,
  10306. IN BOOL ReplacementChannel,
  10307. IN BOOL UseWinHttp,
  10308. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials, OPTIONAL
  10309. IN ULONG ChosenAuthScheme, OPTIONAL
  10310. IN HTTP2WinHttpTransportChannel *WinHttpChannel, OPTIONAL
  10311. IN ULONG CallTimeout,
  10312. IN const BYTE *AdditionalData, OPTIONAL
  10313. IN ULONG AdditionalDataLength OPTIONAL
  10314. )
  10315. /*++
  10316. Routine Description:
  10317. Sends the HTTP establishment header on
  10318. the in/out channel.
  10319. Arguments:
  10320. Hint - the resolver hint
  10321. Verb - the verb to use.
  10322. VerbLength - the length of the verb (in characters, not including
  10323. null terminator).
  10324. InChannel - non-zero if this is an in channel open. In such case we use
  10325. the channel lifetime as the content length. If 0, this is an out
  10326. channel and we use the real content length + some additional space.
  10327. The additional space depends on the ReplacementChannel parameter
  10328. ReplacementChannel - non-zero if this is a replacement channel. Zero
  10329. otherwise. If it is a replacement channel, we add the size of D4/A3.
  10330. Else, we use the size of D1/A1. This is valid only for out channels
  10331. UseWinHttp - non-zero if we should use WinHttp for bottom level communications
  10332. HttpCredentials - the encrypted Http Credentials to use. Ignored unless UseWinHttp
  10333. is non-zero.
  10334. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  10335. WinHttpChannel - the winhttp channel to use for opening. Ignored unless UseWinHttp
  10336. is non-zero.
  10337. CallTimeout - the call timeout for this call.
  10338. AdditionalData - additional data to send with the header. Must be set iff
  10339. AdditionalDataLength != 0
  10340. AdditionalDataLength - the length of the additional data to send with the header.
  10341. Must be set iff AdditionalLength != NULL
  10342. Return Value:
  10343. RPC_S_OK or RPC_S_* error
  10344. --*/
  10345. {
  10346. ULONG MemorySize;
  10347. char *Buffer;
  10348. RPC_CHAR *BufferW;
  10349. RPC_CHAR *OriginalBufferW;
  10350. RPC_CHAR *VerbW;
  10351. char *Header;
  10352. char ServerPortString[6];
  10353. ULONG ServerPortStringLength;
  10354. HTTP2SendContext *SendContext;
  10355. RPC_STATUS RpcStatus;
  10356. char ContentLengthString[6];
  10357. ULONG AdditionalLength;
  10358. ULONG ContentLengthStringLength; // without terminating NULL
  10359. char *ContentLengthToUse;
  10360. // we have plenty of parameters. Verify them
  10361. // We can't have chosen auth scheme without credentials
  10362. // or WinHttpChannel
  10363. if (ChosenAuthScheme)
  10364. {
  10365. ASSERT(HttpCredentials);
  10366. ASSERT(WinHttpChannel);
  10367. }
  10368. // we can't have additional data without data and vice versa
  10369. if (AdditionalData)
  10370. {
  10371. ASSERT(AdditionalDataLength);
  10372. }
  10373. else
  10374. {
  10375. ASSERT(AdditionalDataLength == 0);
  10376. }
  10377. PortNumberToEndpointA(Hint->ServerPort, ServerPortString);
  10378. ServerPortStringLength = RpcpStringLengthA(ServerPortString);
  10379. // determine the content length
  10380. if (AdditionalData)
  10381. {
  10382. AdditionalLength = AdditionalDataLength;
  10383. if (!UseWinHttp)
  10384. {
  10385. RpcpItoa(AdditionalLength, ContentLengthString, 10);
  10386. ContentLengthStringLength = RpcpStringLengthA(ContentLengthString);
  10387. ContentLengthToUse = ContentLengthString;
  10388. }
  10389. }
  10390. else
  10391. {
  10392. if (InChannel == FALSE)
  10393. {
  10394. if (ReplacementChannel)
  10395. AdditionalLength = GetD4_A3TotalLength() + GetD4_A11TotalLength();
  10396. else
  10397. AdditionalLength = GetD1_A1TotalLength();
  10398. if (!UseWinHttp)
  10399. {
  10400. RpcpItoa(AdditionalLength, ContentLengthString, 10);
  10401. ContentLengthStringLength = RpcpStringLengthA(ContentLengthString);
  10402. ContentLengthToUse = ContentLengthString;
  10403. }
  10404. }
  10405. else
  10406. {
  10407. if (UseWinHttp)
  10408. {
  10409. AdditionalLength = DefaultChannelLifetime;
  10410. }
  10411. else
  10412. {
  10413. ContentLengthStringLength = DefaultChannelLifetimeStringLength;
  10414. ContentLengthToUse = DefaultChannelLifetimeString;
  10415. }
  10416. }
  10417. }
  10418. if (UseWinHttp)
  10419. {
  10420. ASSERT(WinHttpChannel != NULL);
  10421. VerbW = new RPC_CHAR[VerbLength + 1];
  10422. if (VerbW == NULL)
  10423. return RPC_S_OUT_OF_MEMORY;
  10424. FullAnsiToUnicode((char *)Verb, VerbW);
  10425. MemorySize = HeaderFragment2Length
  10426. + Hint->ServerNameLength
  10427. + HeaderFragment3Length
  10428. + ServerPortStringLength
  10429. + 1
  10430. ;
  10431. BufferW = (RPC_CHAR *)RpcAllocateBuffer(MemorySize * sizeof(RPC_CHAR));
  10432. if (BufferW == NULL)
  10433. {
  10434. delete [] VerbW;
  10435. return RPC_S_OUT_OF_MEMORY;
  10436. }
  10437. OriginalBufferW = BufferW;
  10438. RpcpMemoryCopy(BufferW, HeaderFragment2W, HeaderFragment2WLength);
  10439. BufferW += HeaderFragment2Length;
  10440. FullAnsiToUnicode(Hint->RpcServer, BufferW);
  10441. BufferW += Hint->ServerNameLength;
  10442. RpcpMemoryCopy(BufferW, HeaderFragment3W, HeaderFragment3WLength);
  10443. BufferW += HeaderFragment3Length;
  10444. FullAnsiToUnicode(ServerPortString, BufferW);
  10445. RpcStatus = WinHttpChannel->Open (Hint,
  10446. VerbW,
  10447. OriginalBufferW, // Url
  10448. HeaderAcceptType,
  10449. AdditionalLength,
  10450. CallTimeout,
  10451. HttpCredentials,
  10452. ChosenAuthScheme,
  10453. AdditionalData
  10454. );
  10455. delete [] VerbW;
  10456. RpcFreeBuffer(OriginalBufferW);
  10457. }
  10458. else
  10459. {
  10460. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext)
  10461. + VerbLength
  10462. + HeaderFragment1Length
  10463. + Hint->ProxyNameLength
  10464. + HeaderFragment2Length
  10465. + Hint->ServerNameLength
  10466. + HeaderFragment3Length
  10467. + ServerPortStringLength
  10468. + HeaderFragment4Length
  10469. + Hint->ProxyNameLength
  10470. + HeaderFragment5Length
  10471. + ContentLengthStringLength
  10472. + HeaderFragment6Length
  10473. ;
  10474. if (AdditionalDataLength)
  10475. MemorySize += AdditionalDataLength;
  10476. Buffer = (char *)RpcAllocateBuffer(MemorySize);
  10477. if (Buffer == NULL)
  10478. return RPC_S_OUT_OF_MEMORY;
  10479. SendContext = (HTTP2SendContext *)Buffer;
  10480. Buffer += SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext);
  10481. Header = Buffer;
  10482. RpcpMemoryCopy(Buffer, Verb, VerbLength);
  10483. Buffer += VerbLength;
  10484. RpcpMemoryCopy(Buffer, HeaderFragment1, HeaderFragment1Length);
  10485. Buffer += HeaderFragment1Length;
  10486. RpcpMemoryCopy(Buffer, Hint->RpcProxy, Hint->ProxyNameLength);
  10487. Buffer += Hint->ProxyNameLength;
  10488. RpcpMemoryCopy(Buffer, HeaderFragment2, HeaderFragment2Length);
  10489. Buffer += HeaderFragment2Length;
  10490. RpcpMemoryCopy(Buffer, Hint->RpcServer, Hint->ServerNameLength);
  10491. Buffer += Hint->ServerNameLength;
  10492. RpcpMemoryCopy(Buffer, HeaderFragment3, HeaderFragment3Length);
  10493. Buffer += HeaderFragment3Length;
  10494. RpcpMemoryCopy(Buffer, ServerPortString, ServerPortStringLength);
  10495. Buffer += ServerPortStringLength;
  10496. RpcpMemoryCopy(Buffer, HeaderFragment4, HeaderFragment4Length);
  10497. Buffer += HeaderFragment4Length;
  10498. RpcpMemoryCopy(Buffer, Hint->RpcProxy, Hint->ProxyNameLength);
  10499. Buffer += Hint->ProxyNameLength;
  10500. RpcpMemoryCopy(Buffer, HeaderFragment5, HeaderFragment5Length);
  10501. Buffer += HeaderFragment5Length;
  10502. RpcpMemoryCopy(Buffer, ContentLengthToUse, ContentLengthStringLength);
  10503. Buffer += ContentLengthStringLength;
  10504. RpcpMemoryCopy(Buffer, HeaderFragment6, HeaderFragment6Length);
  10505. if (AdditionalDataLength)
  10506. {
  10507. Buffer += HeaderFragment6Length;
  10508. RpcpMemoryCopy(Buffer, AdditionalData, AdditionalDataLength);
  10509. }
  10510. #if DBG
  10511. SendContext->ListEntryUsed = FALSE;
  10512. #endif
  10513. SendContext->maxWriteBuffer = MemorySize - SIZE_OF_OBJECT_AND_PADDING(HTTP2SendContext);
  10514. SendContext->pWriteBuffer = (BUFFER)Header;
  10515. SendContext->u.SyncEvent = NULL;
  10516. SendContext->TrafficType = http2ttRaw;
  10517. SendContext->Flags = 0;
  10518. SendContext->UserData = 0;
  10519. RpcStatus = BeginSubmitAsync();
  10520. if (RpcStatus != RPC_S_OK)
  10521. {
  10522. RpcFreeBuffer(SendContext);
  10523. return RpcStatus;
  10524. }
  10525. RpcStatus = LowerLayer->Send(SendContext);
  10526. FinishSubmitAsync();
  10527. if (RpcStatus != RPC_S_OK)
  10528. {
  10529. RpcFreeBuffer(SendContext);
  10530. RemoveReference();
  10531. }
  10532. }
  10533. return RpcStatus;
  10534. }
  10535. RPC_STATUS HTTP2ClientChannel::SendComplete (
  10536. IN RPC_STATUS EventStatus,
  10537. IN OUT HTTP2SendContext *SendContext
  10538. )
  10539. /*++
  10540. Routine Description:
  10541. Send complete notification
  10542. Arguments:
  10543. EventStatus - the status of the send
  10544. SendContext - send context
  10545. Return Value:
  10546. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10547. --*/
  10548. {
  10549. RPC_STATUS RpcStatus;
  10550. HTTP2VirtualConnection *VirtualConnection;
  10551. RpcStatus = HTTP2Channel::CheckSendCompleteForSync(EventStatus,
  10552. SendContext
  10553. );
  10554. if (RpcStatus != RPC_P_PACKET_CONSUMED)
  10555. {
  10556. // is this our client open packet?
  10557. if (SendContext->TrafficType == http2ttRaw)
  10558. {
  10559. if (EventStatus != RPC_S_OK)
  10560. {
  10561. VirtualConnection = (HTTP2VirtualConnection *)LockParentPointer();
  10562. if (VirtualConnection != NULL)
  10563. {
  10564. VirtualConnection->Abort();
  10565. UnlockParentPointer();
  10566. }
  10567. }
  10568. RpcFreeBuffer(SendContext);
  10569. RpcStatus = RPC_P_PACKET_CONSUMED;
  10570. }
  10571. else if (RpcStatus == RPC_S_OK)
  10572. {
  10573. // doesn't seem like our traffic. Forward it up.
  10574. RpcStatus = ForwardUpSendComplete(EventStatus,
  10575. SendContext
  10576. );
  10577. }
  10578. else
  10579. {
  10580. // must be an error - just fall through
  10581. }
  10582. }
  10583. return RpcStatus;
  10584. }
  10585. RPC_STATUS HTTP2ClientChannel::CheckReceiveCompleteForSync (
  10586. IN RPC_STATUS EventStatus,
  10587. IN HTTP2TrafficType TrafficType,
  10588. IN BYTE *Buffer,
  10589. IN UINT BufferLength
  10590. )
  10591. /*++
  10592. Routine Description:
  10593. Receive complete notification. Checks if the receive was
  10594. sync, and if yes, fires event and consumes the packet.
  10595. Arguments:
  10596. EventStatus - status of the operation
  10597. TrafficType - the type of traffic we received
  10598. Buffer - the received buffer (success only)
  10599. BufferLength - the length of the received buffer (success only)
  10600. Return Value:
  10601. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10602. --*/
  10603. {
  10604. HANDLE hEvent;
  10605. // RTS receives are never sync even if there
  10606. // is a sync waiter
  10607. if (TrafficType == http2ttRTS)
  10608. return RPC_S_OK;
  10609. // was this a sync receive?
  10610. if (Ol.ReceiveOverlapped.hEvent)
  10611. {
  10612. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_CHECK_RECV_COMPLETE, HTTP2LOG_OT_CLIENT_CHANNEL, (ULONG_PTR)Buffer);
  10613. // yes, consume it
  10614. if (EventStatus == RPC_S_OK)
  10615. {
  10616. ASSERT(Buffer != NULL);
  10617. }
  10618. Ol.ReceiveOverlapped.Buffer = Buffer;
  10619. Ol.ReceiveOverlapped.BufferLength = BufferLength;
  10620. hEvent = Ol.ReceiveOverlapped.hEvent;
  10621. Ol.ReceiveOverlapped.Internal = (ULONG)EventStatus;
  10622. Ol.ReceiveOverlapped.IOCompleted = TRUE;
  10623. SetEvent(hEvent);
  10624. return RPC_P_PACKET_CONSUMED;
  10625. }
  10626. // wasn't for us after all. Let it continue
  10627. return RPC_S_OK;
  10628. }
  10629. void HTTP2ClientChannel::WaitInfiniteForSyncReceive (
  10630. void
  10631. )
  10632. /*++
  10633. Routine Description:
  10634. Waits infinitely for a sync recv to complete.
  10635. Channel must be aborted before this is called.
  10636. Arguments:
  10637. Return Value:
  10638. --*/
  10639. {
  10640. ASSERT(Aborted.GetInteger() > 0);
  10641. UTIL_WaitForSyncHTTP2IO(&Ol.Overlapped,
  10642. Ol.ReceiveOverlapped.hEvent,
  10643. FALSE, // Alertable
  10644. INFINITE);
  10645. }
  10646. RPC_STATUS HTTP2ClientChannel::SubmitSyncRecv (
  10647. IN HTTP2TrafficType TrafficType
  10648. )
  10649. /*++
  10650. Routine Description:
  10651. Submits a sync recv.
  10652. Arguments:
  10653. TrafficType - the type of traffic
  10654. Return Value:
  10655. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10656. --*/
  10657. {
  10658. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SYNC_RECV, HTTP2LOG_OT_CLIENT_CHANNEL, TrafficType);
  10659. // transfer the settings from parameters to the receive overlapped
  10660. Ol.ReceiveOverlapped.hEvent = I_RpcTransGetThreadEvent();
  10661. ResetEvent(Ol.ReceiveOverlapped.hEvent);
  10662. Ol.ReceiveOverlapped.IOCompleted = FALSE;
  10663. // submit the actual receive
  10664. return HTTP2Channel::Receive(TrafficType);
  10665. }
  10666. RPC_STATUS HTTP2ClientChannel::WaitForSyncRecv (
  10667. IN BYTE **Buffer,
  10668. IN ULONG *BufferLength,
  10669. IN ULONG Timeout,
  10670. IN ULONG ConnectionTimeout,
  10671. IN BASE_ASYNC_OBJECT *Connection,
  10672. OUT BOOL *AbortNeeded,
  10673. OUT BOOL *IoPending
  10674. )
  10675. /*++
  10676. Routine Description:
  10677. Waits for a sync receive to complete.
  10678. Arguments:
  10679. Buffer - on success will contain the received buffer. On failure
  10680. is undefined.
  10681. BufferLength - on success will contain the length of the buffer.
  10682. On failure is undefined.
  10683. Timeout - the call timeout
  10684. ConnectionTimeout - the connection timeout
  10685. Connection - the transport connection object
  10686. AbortNeeded - must be FALSE on entry. This function will set it to
  10687. non-zero if abort and wait are needed.
  10688. WaitPending - must be FALSE on entry. If on return there is an Io
  10689. pending, it will be set to non-zero
  10690. Return Value:
  10691. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  10692. --*/
  10693. {
  10694. RPC_STATUS RpcStatus;
  10695. DWORD dwActualTimeout;
  10696. BOOL fWaitOnConnectionTimeout;
  10697. BOOL fSetKeepAliveVals;
  10698. KEEPALIVE_TIMEOUT KATimeout;
  10699. RPC_STATUS RpcStatus2;
  10700. ASSERT(*AbortNeeded == FALSE);
  10701. ASSERT(*IoPending == FALSE);
  10702. // if there's a per operation timeout, use the lesser of the operation
  10703. // and connection timeout
  10704. ASSERT(ConnectionTimeout);
  10705. if (Timeout != INFINITE)
  10706. {
  10707. if (Timeout <= ConnectionTimeout)
  10708. {
  10709. dwActualTimeout = Timeout;
  10710. fWaitOnConnectionTimeout = FALSE;
  10711. }
  10712. else
  10713. {
  10714. dwActualTimeout = ConnectionTimeout;
  10715. fWaitOnConnectionTimeout = TRUE;
  10716. }
  10717. }
  10718. else
  10719. {
  10720. // wait on the connection timeout
  10721. dwActualTimeout = ConnectionTimeout;
  10722. fWaitOnConnectionTimeout = TRUE;
  10723. }
  10724. fSetKeepAliveVals = FALSE;
  10725. do
  10726. {
  10727. //
  10728. // Wait for the pending receive to complete
  10729. //
  10730. RpcStatus = UTIL_GetOverlappedHTTP2ResultEx(Connection,
  10731. &Ol.Overlapped,
  10732. Ol.ReceiveOverlapped.hEvent,
  10733. TRUE, // Alertable
  10734. dwActualTimeout);
  10735. if (RpcStatus != RPC_S_OK)
  10736. {
  10737. // if we timed out ...
  10738. if (RpcStatus == RPC_P_TIMEOUT)
  10739. {
  10740. ASSERT(dwActualTimeout != INFINITE);
  10741. // if we waited on the per connection timeout ...
  10742. if (fWaitOnConnectionTimeout)
  10743. {
  10744. ASSERT(ConnectionTimeout != INFINITE);
  10745. if (Timeout == INFINITE)
  10746. {
  10747. // enable keep alives and wait forever
  10748. dwActualTimeout = INFINITE;
  10749. }
  10750. else
  10751. {
  10752. ASSERT(ConnectionTimeout < Timeout);
  10753. // enable keep alives and wait the difference
  10754. dwActualTimeout = Timeout - ConnectionTimeout;
  10755. fWaitOnConnectionTimeout = FALSE;
  10756. }
  10757. // Enable aggressive keepalives on the socket if lower layers
  10758. // support it.
  10759. KATimeout.Milliseconds = ConnectionTimeout;
  10760. RpcStatus2 = SetKeepAliveTimeout (
  10761. TRUE, // TurnOn
  10762. FALSE, // bProtectIO
  10763. tuMilliseconds,
  10764. KATimeout,
  10765. KATimeout.Milliseconds
  10766. );
  10767. if (RpcStatus2 != RPC_S_OK)
  10768. {
  10769. *AbortNeeded = TRUE;
  10770. *IoPending = TRUE;
  10771. goto CleanupAndExit;
  10772. }
  10773. fSetKeepAliveVals = TRUE;
  10774. continue;
  10775. }
  10776. // else we have chosen the per operation timeout and
  10777. // have timed out on that - time to bail out
  10778. }
  10779. // Normal error path
  10780. if ((RpcStatus == RPC_S_CALL_CANCELLED) || (RpcStatus == RPC_P_TIMEOUT))
  10781. {
  10782. if ((RpcStatus == RPC_P_TIMEOUT) && fWaitOnConnectionTimeout)
  10783. {
  10784. RpcStatus = RPC_P_RECEIVE_FAILED;
  10785. }
  10786. *AbortNeeded = TRUE;
  10787. *IoPending = TRUE;
  10788. goto CleanupAndExit;
  10789. }
  10790. *AbortNeeded = TRUE;
  10791. // connection was aborted - no need to turn off keep alives
  10792. goto CleanupAndExit;
  10793. }
  10794. }
  10795. while (RpcStatus == RPC_P_TIMEOUT);
  10796. if (fSetKeepAliveVals)
  10797. {
  10798. // Call completed, clear keep alives. Turning off is a best
  10799. // effort. Ignore failures
  10800. KATimeout.Milliseconds = 0;
  10801. (void) SetKeepAliveTimeout(
  10802. FALSE, // TurnOn
  10803. FALSE, // bProtectIO
  10804. tuMilliseconds,
  10805. KATimeout,
  10806. KATimeout.Milliseconds
  10807. );
  10808. }
  10809. *Buffer = Ol.ReceiveOverlapped.Buffer;
  10810. *BufferLength = Ol.ReceiveOverlapped.BufferLength;
  10811. if (RpcStatus == RPC_S_OK)
  10812. {
  10813. ASSERT(*Buffer != NULL);
  10814. }
  10815. CleanupAndExit:
  10816. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SYNC_RECV, HTTP2LOG_OT_CLIENT_CHANNEL, RpcStatus);
  10817. if (*IoPending == FALSE)
  10818. {
  10819. // consume the event if there will be no wait
  10820. Ol.ReceiveOverlapped.hEvent = NULL;
  10821. }
  10822. return RpcStatus;
  10823. }
  10824. void HTTP2ClientChannel::AbortConnection (
  10825. IN RPC_STATUS AbortReason
  10826. )
  10827. /*++
  10828. Routine Description:
  10829. Aborts the client virtual connection. The only
  10830. difference from HTTP2Channel::AbortConnection
  10831. is that it specifically calls AbortChannels on
  10832. the client virtual connection. This is necessary
  10833. because AbortChannels is not virtual.
  10834. Arguments:
  10835. RpcStatus - the error to abort with
  10836. Return Value:
  10837. --*/
  10838. {
  10839. HTTP2ClientVirtualConnection *VirtualConnection;
  10840. // abort the parent connection
  10841. VirtualConnection = (HTTP2ClientVirtualConnection *)LockParentPointer();
  10842. if (VirtualConnection)
  10843. {
  10844. VirtualConnection->AbortChannels(AbortReason);
  10845. UnlockParentPointer();
  10846. }
  10847. else
  10848. {
  10849. // abort this channel at least
  10850. Abort(AbortReason);
  10851. }
  10852. }
  10853. /*********************************************************************
  10854. HTTP2ClientInChannel
  10855. *********************************************************************/
  10856. RPC_STATUS HTTP2ClientInChannel::ClientOpen (
  10857. IN HTTPResolverHint *Hint,
  10858. IN const char *Verb,
  10859. IN int VerbLength,
  10860. IN BOOL UseWinHttp,
  10861. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  10862. IN ULONG ChosenAuthScheme,
  10863. IN ULONG CallTimeout,
  10864. IN const BYTE *AdditionalData, OPTIONAL
  10865. IN ULONG AdditionalDataLength OPTIONAL
  10866. )
  10867. /*++
  10868. Routine Description:
  10869. Sends the HTTP establishment header on
  10870. the in channel.
  10871. Arguments:
  10872. Hint - the resolver hint
  10873. Verb - the verb to use.
  10874. VerbLength - the length of the verb (in characters, not including
  10875. null terminator).
  10876. UseWinHttp - non-zero if WinHttp needs to be used. 0 otherwise
  10877. HttpCredentials - encrypted transport credentials
  10878. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  10879. CallTimeout - the call timeout for this call
  10880. AdditionalData - additional data to send with the header. Must be set iff
  10881. AdditionalDataLength != 0
  10882. AdditionalDataLength - the length of the additional data to send with the header.
  10883. Must be set iff AdditionalLength != NULL
  10884. Return Value:
  10885. RPC_S_OK or RPC_S_* error
  10886. --*/
  10887. {
  10888. return HTTP2ClientChannel::ClientOpen(Hint,
  10889. Verb,
  10890. VerbLength,
  10891. TRUE, // InChannel
  10892. FALSE, // ReplacementChannel
  10893. UseWinHttp,
  10894. HttpCredentials,
  10895. ChosenAuthScheme,
  10896. GetWinHttpConnection(),
  10897. CallTimeout,
  10898. AdditionalData,
  10899. AdditionalDataLength
  10900. );
  10901. }
  10902. RPC_STATUS HTTP2ClientInChannel::SetKeepAliveTimeout (
  10903. IN BOOL TurnOn,
  10904. IN BOOL bProtectIO,
  10905. IN KEEPALIVE_TIMEOUT_UNITS Units,
  10906. IN OUT KEEPALIVE_TIMEOUT KATime,
  10907. IN ULONG KAInterval OPTIONAL
  10908. )
  10909. /*++
  10910. Routine Description:
  10911. Change the keep alive value on the channel
  10912. Arguments:
  10913. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  10914. are turned off.
  10915. bProtectIO - non-zero if IO needs to be protected against async close
  10916. of the connection.
  10917. Units - in what units is KATime
  10918. KATime - how much to wait before turning on keep alives
  10919. KAInterval - the interval between keep alives
  10920. Return Value:
  10921. RPC_S_OK or other RPC_S_* errors for error.
  10922. May return RPC_P_CHANNEL_NEEDS_RECYCLING - caller needs to handle.
  10923. --*/
  10924. {
  10925. HTTP2SendContext *KeepAliveChangeContext;
  10926. RPC_STATUS RpcStatus;
  10927. BOOL WasChannelRecyclingTriggered;
  10928. ASSERT(Units == tuMilliseconds);
  10929. // HTTP keep alives are heavy weight. Moderate the caller's
  10930. // settings
  10931. if (TurnOn)
  10932. {
  10933. if (KAInterval < MinimumClientSideKeepAliveInterval)
  10934. KAInterval = MinimumClientSideKeepAliveInterval;
  10935. }
  10936. else
  10937. {
  10938. KAInterval = 0;
  10939. }
  10940. // tell the proxy to change it's keepalives and then
  10941. // ask our ping originator to change its keepalives as well
  10942. KeepAliveChangeContext = AllocateAndInitializeKeepAliveChangePacket (KAInterval);
  10943. if (KeepAliveChangeContext == NULL)
  10944. return RPC_S_OUT_OF_MEMORY;
  10945. RpcStatus = Send(KeepAliveChangeContext);
  10946. WasChannelRecyclingTriggered = FALSE;
  10947. if (RpcStatus != RPC_S_OK)
  10948. {
  10949. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  10950. WasChannelRecyclingTriggered = TRUE;
  10951. else
  10952. {
  10953. FreeRTSPacket(KeepAliveChangeContext);
  10954. return RpcStatus;
  10955. }
  10956. }
  10957. // get into submission context
  10958. RpcStatus = BeginSimpleSubmitAsync();
  10959. if (RpcStatus != RPC_S_OK)
  10960. return RpcStatus;
  10961. // ask our ping channel to change as well
  10962. RpcStatus = GetPingOriginatorChannel()->SetKeepAliveTimeout (
  10963. TurnOn,
  10964. bProtectIO,
  10965. Units,
  10966. KATime,
  10967. KAInterval
  10968. );
  10969. FinishSubmitAsync();
  10970. // if we failed for other reasons or channel recycling was not triggered
  10971. // at all, return the current status
  10972. if ((WasChannelRecyclingTriggered == FALSE) || (RpcStatus != RPC_S_OK))
  10973. return RpcStatus;
  10974. else
  10975. return RPC_P_CHANNEL_NEEDS_RECYCLING;
  10976. }
  10977. /*********************************************************************
  10978. HTTP2ClientOutChannel
  10979. *********************************************************************/
  10980. RPC_STATUS HTTP2ClientOutChannel::ClientOpen (
  10981. IN HTTPResolverHint *Hint,
  10982. IN const char *Verb,
  10983. IN int VerbLength,
  10984. IN BOOL ReplacementChannel,
  10985. IN BOOL UseWinHttp,
  10986. IN RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials,
  10987. IN ULONG ChosenAuthScheme,
  10988. IN ULONG CallTimeout,
  10989. IN const BYTE *AdditionalData, OPTIONAL
  10990. IN ULONG AdditionalDataLength OPTIONAL
  10991. )
  10992. /*++
  10993. Routine Description:
  10994. Sends the HTTP establishment header on
  10995. the out channel.
  10996. Arguments:
  10997. Hint - the resolver hint
  10998. Verb - the verb to use.
  10999. VerbLength - the length of the verb (in characters, not including
  11000. null terminator).
  11001. ReplacementChannel - non-zero if this is a replacement channel.
  11002. Zero if it is not.
  11003. UseWinHttp - non-zero if WinHttp needs to be used. 0 otherwise
  11004. HttpCredentials - encrypted transport credentials
  11005. ChosenAuthScheme - the chosen auth scheme. 0 if no auth scheme is chosen.
  11006. CallTimeout - the call timeout for this call.
  11007. AdditionalData - additional data to send with the header. Must be set iff
  11008. AdditionalDataLength != 0
  11009. AdditionalDataLength - the length of the additional data to send with the header.
  11010. Must be set iff AdditionalLength != NULL
  11011. Return Value:
  11012. RPC_S_OK or RPC_S_* error
  11013. --*/
  11014. {
  11015. return HTTP2ClientChannel::ClientOpen(Hint,
  11016. Verb,
  11017. VerbLength,
  11018. FALSE, // InChannel
  11019. ReplacementChannel,
  11020. UseWinHttp,
  11021. HttpCredentials,
  11022. ChosenAuthScheme,
  11023. GetWinHttpConnection(),
  11024. CallTimeout,
  11025. AdditionalData,
  11026. AdditionalDataLength
  11027. );
  11028. }
  11029. RPC_STATUS HTTP2ClientOutChannel::ForwardFlowControlAck (
  11030. IN ULONG BytesReceivedForAck,
  11031. IN ULONG WindowForAck
  11032. )
  11033. /*++
  11034. Routine Description:
  11035. Forwards a flow control ack to the out proxy through the in proxy
  11036. Arguments:
  11037. BytesReceivedForAck - the bytes received when the ACK was issued
  11038. WindowForAck - the free window when the ACK was issued.
  11039. Return Value:
  11040. RPC_S_OK or RPC_S_*
  11041. Notes:
  11042. Must be called from neutral context only.
  11043. --*/
  11044. {
  11045. RPC_STATUS RpcStatus;
  11046. RpcStatus = ForwardFlowControlAckOnDefaultChannel(TRUE, // IsInChannel
  11047. fdOutProxy,
  11048. BytesReceivedForAck,
  11049. WindowForAck
  11050. );
  11051. RpcStatus = HandleSendResultFromNeutralContext(RpcStatus);
  11052. return RpcStatus;
  11053. }
  11054. RPC_STATUS HTTP2ClientOutChannel::SetKeepAliveTimeout (
  11055. IN BOOL TurnOn,
  11056. IN BOOL bProtectIO,
  11057. IN KEEPALIVE_TIMEOUT_UNITS Units,
  11058. IN OUT KEEPALIVE_TIMEOUT KATime,
  11059. IN ULONG KAInterval OPTIONAL
  11060. )
  11061. /*++
  11062. Routine Description:
  11063. Change the keep alive value on the channel
  11064. Arguments:
  11065. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  11066. are turned off.
  11067. bProtectIO - non-zero if IO needs to be protected against async close
  11068. of the connection.
  11069. Units - in what units is KATime
  11070. KATime - how much to wait before turning on keep alives
  11071. KAInterval - the interval between keep alives
  11072. Return Value:
  11073. RPC_S_OK or other RPC_S_* errors for error
  11074. --*/
  11075. {
  11076. HTTP2ClientVirtualConnection *VirtualConnection;
  11077. RPC_STATUS RpcStatus;
  11078. // turn around the request through the connection
  11079. VirtualConnection = LockParentPointer();
  11080. if (VirtualConnection == NULL)
  11081. return RPC_P_CONNECTION_SHUTDOWN;
  11082. RpcStatus = VirtualConnection->TurnOnOffKeepAlives(
  11083. TurnOn,
  11084. bProtectIO,
  11085. TRUE, // IsFromUpcall
  11086. Units,
  11087. KATime,
  11088. KAInterval
  11089. );
  11090. UnlockParentPointer();
  11091. return RpcStatus;
  11092. }
  11093. /*********************************************************************
  11094. HTTP2ClientVirtualConnection
  11095. *********************************************************************/
  11096. RPC_STATUS HTTP2ClientVirtualConnection::ClientOpen (
  11097. IN HTTPResolverHint *Hint,
  11098. IN BOOL HintWasInitialized,
  11099. IN UINT ConnTimeout,
  11100. IN ULONG CallTimeout
  11101. )
  11102. /*++
  11103. Routine Description:
  11104. Opens a client side virtual connection.
  11105. Arguments:
  11106. Hint - the resolver hint
  11107. HintWasInitialized - the hint was initialized on input.
  11108. ConnTimeout - connection timeout
  11109. CallTimeout - operation timeout
  11110. Return Value:
  11111. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  11112. --*/
  11113. {
  11114. return ClientOpenInternal (
  11115. Hint,
  11116. HintWasInitialized,
  11117. ConnTimeout,
  11118. CallTimeout,
  11119. TRUE, // OpenInChannel
  11120. TRUE, // OpenOutChannel
  11121. FALSE, // IsReplacementChannel
  11122. FALSE // IsFromUpcall
  11123. );
  11124. }
  11125. RPC_STATUS HTTP2ClientVirtualConnection::SendComplete (
  11126. IN RPC_STATUS EventStatus,
  11127. IN OUT HTTP2SendContext *SendContext,
  11128. IN int ChannelId
  11129. )
  11130. /*++
  11131. Routine Description:
  11132. Called by lower layers to indicate send complete.
  11133. Arguments:
  11134. EventStatus - status of the operation
  11135. SendContext - the context for the send complete
  11136. ChannelId - which channel completed the operation
  11137. Return Value:
  11138. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  11139. be hidden from the runtime.
  11140. RPC_S_OK if the packet was processed successfully.
  11141. RPC_S_* error if there was an error while processing the
  11142. packet.
  11143. --*/
  11144. {
  11145. HTTP2TrafficType TrafficType;
  11146. VerifyValidChannelId(ChannelId);
  11147. if (EventStatus == RPC_S_OK)
  11148. {
  11149. // successful sends are always no-ops on the
  11150. // client. Just cleanup if necessary and
  11151. // return
  11152. if (SendContext->TrafficType == http2ttRTS)
  11153. {
  11154. FreeSendContextAndPossiblyData(SendContext);
  11155. return RPC_P_PACKET_CONSUMED;
  11156. }
  11157. else
  11158. return RPC_S_OK;
  11159. }
  11160. // we know the send failed
  11161. if (IsDefaultInChannel(ChannelId) || IsDefaultOutChannel(ChannelId))
  11162. {
  11163. // on a default channel such error is fatal
  11164. AbortChannels(EventStatus);
  11165. if (SendContext->TrafficType == http2ttRTS)
  11166. {
  11167. FreeSendContextAndPossiblyData(SendContext);
  11168. return RPC_P_PACKET_CONSUMED;
  11169. }
  11170. ASSERT(SendContext->TrafficType == http2ttData);
  11171. return EventStatus;
  11172. }
  11173. else
  11174. {
  11175. // all data sends go on default channels. RTS sends
  11176. // may go either way. If this is RTS, this is fatal.
  11177. // Otherwise, ignore.
  11178. if (SendContext->TrafficType == http2ttRTS)
  11179. {
  11180. FreeSendContextAndPossiblyData(SendContext);
  11181. AbortChannels(EventStatus);
  11182. return RPC_P_PACKET_CONSUMED;
  11183. }
  11184. else
  11185. return RPC_S_OK;
  11186. }
  11187. }
  11188. RPC_STATUS HTTP2ClientVirtualConnection::ReceiveComplete (
  11189. IN RPC_STATUS EventStatus,
  11190. IN BYTE *Buffer,
  11191. IN UINT BufferLength,
  11192. IN int ChannelId
  11193. )
  11194. /*++
  11195. Routine Description:
  11196. Called by lower layers to indicate receive complete
  11197. Arguments:
  11198. EventStatus - RPC_S_OK for success or RPC_S_* for error
  11199. Buffer - buffer received
  11200. BufferLength - length of buffer received
  11201. ChannelId - which channel completed the operation
  11202. Return Value:
  11203. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  11204. be hidden from the runtime.
  11205. RPC_P_ABORT_NEEDED - if the channel needs to be aborted but
  11206. couldn't be aborted in this function because it was detached.
  11207. After aborting, the semantics is same as RPC_P_PACKET_CONSUMED.
  11208. RPC_S_OK if the packet was processed successfully.
  11209. RPC_S_* error if there was an error while processing the
  11210. packet.
  11211. --*/
  11212. {
  11213. RPC_STATUS RpcStatus;
  11214. ULONG ProxyConnectionTimeout;
  11215. BOOL BufferFreed = FALSE;
  11216. BOOL WakeOpenThread;
  11217. HTTP2ClientInChannel *InChannel;
  11218. HTTP2ClientOutChannel *OutChannel;
  11219. HTTP2ClientOutChannel *OutChannel2;
  11220. HTTP2ClientInChannel *NewInChannel;
  11221. HTTP2ChannelPointer *ChannelPtr;
  11222. HTTP2ChannelPointer *NewChannelPtr;
  11223. LIST_ENTRY NewBufferHead;
  11224. LIST_ENTRY *CurrentListEntry;
  11225. LIST_ENTRY *PrevListEntry;
  11226. HTTP2SendContext *QueuedSendContext;
  11227. BOOL MutexReleased;
  11228. HTTP2SendContext *A5Context; // may be D2/A5 or D3/A5
  11229. HTTP2SendContext *D4_A7Context;
  11230. HTTP2SendContext *PingContext;
  11231. BOOL IsD2_A4;
  11232. HTTP2ClientOpenedPacketType ClientPacketType;
  11233. BOOL DataReceivePosted;
  11234. HTTP2StateValues NewState;
  11235. HTTP2StateValues ExpectedState;
  11236. ULONG BytesReceivedForAck;
  11237. ULONG WindowForAck;
  11238. HTTP2Cookie CookieForChannel;
  11239. ULONG InProxyReceiveWindow;
  11240. BOOL UseWinHttp;
  11241. KEEPALIVE_TIMEOUT KATimeout;
  11242. VerifyValidChannelId(ChannelId);
  11243. if (
  11244. (InChannelState.State == http2svSearchProxy)
  11245. &&
  11246. (
  11247. (EventStatus != RPC_S_OK)
  11248. ||
  11249. IsEchoPacket(Buffer, BufferLength)
  11250. )
  11251. )
  11252. {
  11253. InChannelState.Mutex.Request();
  11254. if (InChannelState.State == http2svSearchProxy)
  11255. {
  11256. InChannelState.Mutex.Clear();
  11257. if (IsInChannel(ChannelId))
  11258. {
  11259. InOpenStatus = EventStatus;
  11260. }
  11261. else
  11262. {
  11263. OutOpenStatus = EventStatus;
  11264. }
  11265. // we won the race. Wake up the open thread
  11266. WakeOpenThread = TRUE;
  11267. RpcStatus = RPC_P_PACKET_CONSUMED;
  11268. goto CleanupAndExit;
  11269. }
  11270. InChannelState.Mutex.Clear();
  11271. }
  11272. WakeOpenThread = FALSE;
  11273. if (IsInChannel(ChannelId))
  11274. {
  11275. if (EventStatus != RPC_P_AUTH_NEEDED)
  11276. {
  11277. // we shouldn't really be receiving stuff on the in channel
  11278. // unless there is an error
  11279. if (EventStatus != RPC_S_OK)
  11280. {
  11281. if (IsDefaultInChannel(ChannelId) == FALSE)
  11282. {
  11283. InChannelState.Mutex.Request();
  11284. if (InChannelState.State == http2svOpened)
  11285. {
  11286. // close on the non-default channel in open
  11287. // state is not an error for the connection
  11288. // just abort the channel in question
  11289. InChannelState.Mutex.Clear();
  11290. ChannelPtr = GetChannelPointerFromId(ChannelId);
  11291. InChannel = (HTTP2ClientInChannel *)ChannelPtr->LockChannelPointer();
  11292. if (InChannel)
  11293. {
  11294. InChannel->Abort(EventStatus);
  11295. ChannelPtr->UnlockChannelPointer();
  11296. RpcStatus = RPC_P_PACKET_CONSUMED;
  11297. }
  11298. else
  11299. RpcStatus = RPC_P_ABORT_NEEDED;
  11300. BufferFreed = TRUE;
  11301. return RpcStatus;
  11302. }
  11303. else
  11304. InChannelState.Mutex.Clear();
  11305. }
  11306. RpcStatus = EventStatus;
  11307. // in failed receives, we don't own the buffer
  11308. BufferFreed = TRUE;
  11309. }
  11310. else
  11311. {
  11312. if (IsEchoPacket(Buffer, BufferLength))
  11313. {
  11314. InOpenStatus = EventStatus;
  11315. WakeOpenThread = TRUE;
  11316. RpcStatus = RPC_P_PACKET_CONSUMED;
  11317. goto CleanupAndExit;
  11318. }
  11319. RpcStatus = RPC_S_PROTOCOL_ERROR;
  11320. }
  11321. AbortChannels(RpcStatus);
  11322. }
  11323. else
  11324. {
  11325. // turn around the error code and fall through
  11326. RpcStatus = EventStatus;
  11327. }
  11328. // the runtime never posted a receive on the in
  11329. // channel. Don't let it see the packet
  11330. InOpenStatus = RpcStatus;
  11331. WakeOpenThread = TRUE;
  11332. RpcStatus = RPC_P_PACKET_CONSUMED;
  11333. }
  11334. else
  11335. {
  11336. // this is an out channel
  11337. if (EventStatus != RPC_S_OK)
  11338. {
  11339. if (EventStatus != RPC_P_AUTH_NEEDED)
  11340. {
  11341. AbortChannels(EventStatus);
  11342. RpcStatus = EventStatus;
  11343. if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  11344. RpcStatus = RPC_P_RECEIVE_FAILED;
  11345. OutOpenStatus = RpcStatus;
  11346. }
  11347. else
  11348. {
  11349. OutOpenStatus = EventStatus;
  11350. RpcStatus = RPC_P_RECEIVE_FAILED;
  11351. }
  11352. WakeOpenThread = TRUE;
  11353. // in failed receives we don't own the buffer
  11354. BufferFreed = TRUE;
  11355. }
  11356. else
  11357. {
  11358. // verify state and act upon it if RTS
  11359. // for data we don't care
  11360. if (IsRTSPacket(Buffer))
  11361. {
  11362. if (IsOtherCmdPacket(Buffer, BufferLength))
  11363. {
  11364. // the only cmd packet we expect is flow control ack
  11365. // try to interpret it as such
  11366. RpcStatus = ParseAndFreeFlowControlAckPacketWithDestination (
  11367. Buffer,
  11368. BufferLength,
  11369. fdClient,
  11370. &BytesReceivedForAck,
  11371. &WindowForAck,
  11372. &CookieForChannel
  11373. );
  11374. BufferFreed = TRUE;
  11375. if (RpcStatus == RPC_S_OK)
  11376. {
  11377. // notify the flow control sender about the ack
  11378. InChannel = (HTTP2ClientInChannel *)MapCookieToChannelPointer(
  11379. &CookieForChannel,
  11380. &ChannelPtr
  11381. );
  11382. if (InChannel && !IsInChannel(ChannelPtr))
  11383. {
  11384. CORRUPTION_ASSERT(0);
  11385. ChannelPtr->UnlockChannelPointer();
  11386. RpcStatus = RPC_S_PROTOCOL_ERROR;
  11387. InChannel = NULL;
  11388. // fall through with the error
  11389. }
  11390. if (InChannel)
  11391. {
  11392. RpcStatus = InChannel->FlowControlAckNotify(BytesReceivedForAck,
  11393. WindowForAck
  11394. );
  11395. ChannelPtr->UnlockChannelPointer();
  11396. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  11397. TRUE // IsFromUpcall
  11398. );
  11399. }
  11400. if (RpcStatus == RPC_S_OK)
  11401. {
  11402. // post another receive
  11403. RpcStatus = PostReceiveOnChannel (GetChannelPointerFromId(ChannelId),
  11404. http2ttRTS
  11405. );
  11406. }
  11407. }
  11408. if (RpcStatus != RPC_S_OK)
  11409. {
  11410. AbortChannels(RpcStatus);
  11411. OutOpenStatus = RpcStatus;
  11412. WakeOpenThread = TRUE;
  11413. }
  11414. // This is an RTS packet - consume it
  11415. RpcStatus = RPC_P_PACKET_CONSUMED;
  11416. goto CleanupAndExit;
  11417. }
  11418. else if (IsEchoPacket(Buffer, BufferLength))
  11419. {
  11420. OutOpenStatus = EventStatus;
  11421. WakeOpenThread = TRUE;
  11422. RpcStatus = RPC_P_PACKET_CONSUMED;
  11423. goto CleanupAndExit;
  11424. }
  11425. RpcStatus = HTTPTransInfo->CreateThread();
  11426. if (RpcStatus != RPC_S_OK)
  11427. {
  11428. AbortChannels(RpcStatus);
  11429. // This is an RTS packet - consume it
  11430. RpcFreeBuffer(Buffer);
  11431. BufferFreed = TRUE;
  11432. OutOpenStatus = RpcStatus;
  11433. WakeOpenThread = TRUE;
  11434. RpcStatus = RPC_P_PACKET_CONSUMED;
  11435. goto CleanupAndExit;
  11436. }
  11437. MutexReleased = FALSE;
  11438. InChannelState.Mutex.Request();
  11439. switch (InChannelState.State)
  11440. {
  11441. case http2svA3W:
  11442. RpcStatus = ParseAndFreeD1_A3(Buffer,
  11443. BufferLength,
  11444. &ProxyConnectionTimeout
  11445. );
  11446. // we don't really do anything with the ProxyConnectionTimeout - it's
  11447. // for debugging purposes only
  11448. BufferFreed = TRUE;
  11449. if (RpcStatus == RPC_S_OK)
  11450. {
  11451. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRTS);
  11452. if (RpcStatus == RPC_S_OK)
  11453. {
  11454. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svC2W, 1, 0);
  11455. InChannelState.State = http2svC2W;
  11456. }
  11457. else
  11458. {
  11459. OutOpenStatus = RpcStatus;
  11460. AbortChannels(RpcStatus);
  11461. WakeOpenThread = TRUE;
  11462. }
  11463. RpcStatus = RPC_P_PACKET_CONSUMED;
  11464. }
  11465. break;
  11466. case http2svC2W:
  11467. RpcStatus = ParseAndFreeD1_C2(Buffer,
  11468. BufferLength,
  11469. &ProtocolVersion,
  11470. &InProxyReceiveWindow,
  11471. &InProxyConnectionTimeout
  11472. );
  11473. BufferFreed = TRUE;
  11474. if (RpcStatus == RPC_S_OK)
  11475. {
  11476. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRTS);
  11477. if (RpcStatus == RPC_S_OK)
  11478. {
  11479. // Set the in proxy timeout to the channel
  11480. InChannel = LockDefaultInChannel(&ChannelPtr);
  11481. if (InChannel != NULL)
  11482. {
  11483. InChannel->SetPeerReceiveWindow(InProxyReceiveWindow);
  11484. RpcStatus = InChannel->SetConnectionTimeout(InProxyConnectionTimeout);
  11485. ChannelPtr->UnlockChannelPointer();
  11486. }
  11487. else
  11488. RpcStatus = RPC_P_CONNECTION_CLOSED;
  11489. if (RpcStatus != RPC_S_OK)
  11490. {
  11491. AbortChannels(RpcStatus);
  11492. OutOpenStatus = RpcStatus;
  11493. WakeOpenThread = TRUE;
  11494. RpcStatus = RPC_P_PACKET_CONSUMED;
  11495. break;
  11496. }
  11497. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  11498. InChannelState.State = http2svOpened;
  11499. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  11500. OutChannelState.State = http2svOpened;
  11501. InOpenStatus = OutOpenStatus = RPC_S_OK;
  11502. SetClientOpenInEvent();
  11503. RpcStatus = RPC_P_PACKET_CONSUMED;
  11504. }
  11505. }
  11506. break;
  11507. default:
  11508. // all the opened states are handled here
  11509. ASSERT((InChannelState.State == http2svOpened)
  11510. || (InChannelState.State == http2svOpened_A4W) );
  11511. ASSERT((OutChannelState.State == http2svOpened)
  11512. || (OutChannelState.State == http2svOpened_A6W)
  11513. || (OutChannelState.State == http2svOpened_A10W)
  11514. || (OutChannelState.State == http2svOpened_B3W) );
  11515. RpcStatus = GetClientOpenedPacketType (Buffer,
  11516. BufferLength,
  11517. &ClientPacketType
  11518. );
  11519. if (RpcStatus != RPC_S_OK)
  11520. {
  11521. AbortChannels(RpcStatus);
  11522. RpcStatus = RPC_P_PACKET_CONSUMED;
  11523. break;
  11524. }
  11525. switch (ClientPacketType)
  11526. {
  11527. case http2coptD2_A4:
  11528. case http2coptD3_A4:
  11529. // in channel must be in Opened_A4W
  11530. // out channel can be in any state
  11531. CORRUPTION_ASSERT(InChannelState.State == http2svOpened_A4W);
  11532. if (InChannelState.State != http2svOpened_A4W)
  11533. {
  11534. InChannelState.Mutex.Clear();
  11535. MutexReleased = TRUE;
  11536. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11537. RpcStatus = RPC_P_PACKET_CONSUMED;
  11538. break;
  11539. }
  11540. InChannelState.Mutex.Clear();
  11541. MutexReleased = TRUE;
  11542. IsD2_A4 = IsD2_A4OrD3_A4(Buffer,
  11543. BufferLength
  11544. );
  11545. if (IsD2_A4)
  11546. {
  11547. RpcStatus = ParseAndFreeD2_A4(Buffer,
  11548. BufferLength,
  11549. fdClient,
  11550. &ProtocolVersion,
  11551. &InProxyReceiveWindow,
  11552. &InProxyConnectionTimeout
  11553. );
  11554. }
  11555. else
  11556. {
  11557. // This must be a D3/A4
  11558. RpcStatus = ParseAndFreeD3_A4 (Buffer,
  11559. BufferLength
  11560. );
  11561. }
  11562. BufferFreed = TRUE;
  11563. if (RpcStatus != RPC_S_OK)
  11564. {
  11565. AbortChannels(RpcStatus);
  11566. RpcStatus = RPC_P_PACKET_CONSUMED;
  11567. break;
  11568. }
  11569. RpcStatus = PostReceiveOnChannel(&OutChannels[DefaultOutChannelSelector],
  11570. http2ttRTS);
  11571. if (RpcStatus != RPC_S_OK)
  11572. {
  11573. AbortChannels(RpcStatus);
  11574. RpcStatus = RPC_P_PACKET_CONSUMED;
  11575. break;
  11576. }
  11577. // lock the old channel
  11578. InChannel = LockDefaultInChannel(&ChannelPtr);
  11579. if (InChannel == NULL)
  11580. {
  11581. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11582. RpcStatus = RPC_P_PACKET_CONSUMED;
  11583. break;
  11584. }
  11585. if (IsD2_A4 == FALSE)
  11586. {
  11587. // capture the receive window from the old channel.
  11588. // We know the proxy is the same so the window must be
  11589. // the same as well
  11590. InProxyReceiveWindow = InChannel->GetPeerReceiveWindow();
  11591. }
  11592. // switch channels (new channel is still plugged)
  11593. SwitchDefaultInChannelSelector();
  11594. // wait for everybody that is in the process of using
  11595. // the old channel to get out
  11596. InChannel->DrainPendingSubmissions();
  11597. // leave 1 for our lock
  11598. ChannelPtr->DrainPendingLocks(1);
  11599. // lock new channel (by now it is default)
  11600. NewInChannel = LockDefaultInChannel(&NewChannelPtr);
  11601. if (NewInChannel == NULL)
  11602. {
  11603. ChannelPtr->UnlockChannelPointer();
  11604. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11605. RpcStatus = RPC_P_PACKET_CONSUMED;
  11606. break;
  11607. }
  11608. NewInChannel->SetPeerReceiveWindow(InProxyReceiveWindow);
  11609. // Set the in proxy timeout to the new channel
  11610. RpcStatus = NewInChannel->SetConnectionTimeout(InProxyConnectionTimeout);
  11611. if (RpcStatus != RPC_S_OK)
  11612. {
  11613. NewChannelPtr->UnlockChannelPointer();
  11614. ChannelPtr->UnlockChannelPointer();
  11615. AbortChannels(RpcStatus);
  11616. RpcStatus = RPC_P_PACKET_CONSUMED;
  11617. break;
  11618. }
  11619. // if old flow control channel was queuing, grab all its buffers
  11620. // We must do this before the channel data originator to make sure
  11621. // the buffers end up behind the ones from the channel data
  11622. // originator
  11623. RpcpInitializeListHead(&NewBufferHead);
  11624. InChannel->GetFlowControlSenderBufferQueue(&NewBufferHead);
  11625. AddBufferQueueToChannel(&NewBufferHead, NewInChannel);
  11626. // GetChannelOriginatorBufferQueue can be called in submission
  11627. // context only. Get into submission context
  11628. RpcStatus = InChannel->BeginSimpleSubmitAsync();
  11629. if (RpcStatus != RPC_S_OK)
  11630. {
  11631. NewChannelPtr->UnlockChannelPointer();
  11632. ChannelPtr->UnlockChannelPointer();
  11633. AbortChannels(RpcStatus);
  11634. RpcStatus = RPC_P_PACKET_CONSUMED;
  11635. break;
  11636. }
  11637. // if old channel channel data originator was queuing, grab all its buffers
  11638. RpcpInitializeListHead(&NewBufferHead);
  11639. InChannel->GetChannelOriginatorBufferQueue(&NewBufferHead);
  11640. InChannel->FinishSubmitAsync();
  11641. AddBufferQueueToChannel(&NewBufferHead, NewInChannel);
  11642. InChannelState.Mutex.Request();
  11643. // move channel state to opened
  11644. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  11645. InChannelState.State = http2svOpened;
  11646. InChannelState.Mutex.Clear();
  11647. if (IsD2_A4)
  11648. {
  11649. // register the last packet to send with the old channel
  11650. A5Context = AllocateAndInitializeD2_A5 (
  11651. &InChannelCookies[DefaultInChannelSelector]
  11652. );
  11653. }
  11654. else
  11655. {
  11656. A5Context = AllocateAndInitializeD3_A5 (
  11657. &InChannelCookies[DefaultInChannelSelector]
  11658. );
  11659. }
  11660. if (A5Context == NULL)
  11661. {
  11662. ChannelPtr->UnlockChannelPointer();
  11663. NewChannelPtr->UnlockChannelPointer();
  11664. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11665. RpcStatus = RPC_P_PACKET_CONSUMED;
  11666. break;
  11667. }
  11668. // make sure the packet is sent last
  11669. RpcStatus = InChannel->Send(A5Context);
  11670. if (RpcStatus == RPC_S_OK)
  11671. {
  11672. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  11673. if (UseWinHttp)
  11674. {
  11675. InChannel->DisablePings();
  11676. RpcStatus = InChannel->Receive(http2ttRaw);
  11677. }
  11678. }
  11679. else
  11680. {
  11681. FreeRTSPacket(A5Context);
  11682. }
  11683. if (RpcStatus != RPC_S_OK)
  11684. {
  11685. ChannelPtr->UnlockChannelPointer();
  11686. NewChannelPtr->UnlockChannelPointer();
  11687. AbortChannels(RPC_P_CONNECTION_CLOSED);
  11688. RpcStatus = RPC_P_PACKET_CONSUMED;
  11689. break;
  11690. }
  11691. // D2_A5 was sent. We must switch the
  11692. // default loopback and detach the channel.
  11693. // Note that we don't abort the channel - we
  11694. // just release the lifetime reference
  11695. // When the proxy closes the connection, then
  11696. // we will abort.
  11697. SwitchDefaultLoopbackChannelSelector();
  11698. ChannelPtr->UnlockChannelPointer();
  11699. ChannelPtr->FreeChannelPointer(
  11700. TRUE, // DrainUpcalls
  11701. FALSE, // CalledFromUpcallContext
  11702. FALSE, // Abort
  11703. RPC_S_OK
  11704. );
  11705. RpcStatus = NewInChannel->Unplug();
  11706. if (RpcStatus != RPC_S_OK)
  11707. {
  11708. NewChannelPtr->UnlockChannelPointer();
  11709. AbortChannels(RpcStatus);
  11710. RpcStatus = RPC_P_PACKET_CONSUMED;
  11711. break;
  11712. }
  11713. NewChannelPtr->UnlockChannelPointer();
  11714. RpcStatus = RPC_P_PACKET_CONSUMED;
  11715. break;
  11716. case http2coptD4_A2:
  11717. // in channel can be in any opened state
  11718. // out channel must be in http2svOpened
  11719. CORRUPTION_ASSERT(OutChannelState.State == http2svOpened);
  11720. if (OutChannelState.State != http2svOpened)
  11721. {
  11722. AbortChannels(RpcStatus);
  11723. RpcStatus = RPC_P_PACKET_CONSUMED;
  11724. break;
  11725. }
  11726. InChannelState.Mutex.Clear();
  11727. MutexReleased = TRUE;
  11728. RpcStatus = ParseAndFreeD4_A2(Buffer,
  11729. BufferLength
  11730. );
  11731. BufferFreed = TRUE;
  11732. if (RpcStatus != RPC_S_OK)
  11733. {
  11734. AbortChannels(RpcStatus);
  11735. RpcStatus = RPC_P_PACKET_CONSUMED;
  11736. break;
  11737. }
  11738. RpcStatus = OpenReplacementOutChannel();
  11739. if (RpcStatus != RPC_S_OK)
  11740. {
  11741. AbortChannels(RpcStatus);
  11742. RpcStatus = RPC_P_PACKET_CONSUMED;
  11743. break;
  11744. }
  11745. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  11746. http2ttRTS);
  11747. if (RpcStatus != RPC_S_OK)
  11748. AbortChannels(RpcStatus);
  11749. RpcStatus = RPC_P_PACKET_CONSUMED;
  11750. break;
  11751. case http2coptD4_A6:
  11752. case http2coptD5_A6:
  11753. // in channel can be in any opened state
  11754. // out channel must be in http2svOpened_A6W
  11755. CORRUPTION_ASSERT(OutChannelState.State == http2svOpened_A6W);
  11756. if (OutChannelState.State != http2svOpened_A6W)
  11757. {
  11758. AbortChannels(RpcStatus);
  11759. RpcStatus = RPC_P_PACKET_CONSUMED;
  11760. break;
  11761. }
  11762. if (ClientPacketType == http2coptD4_A6)
  11763. NewState = http2svOpened_A10W;
  11764. else
  11765. NewState = http2svOpened_B3W;
  11766. // move channel state to new state
  11767. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, NewState, 1, 0);
  11768. OutChannelState.State = NewState;
  11769. InChannelState.Mutex.Clear();
  11770. MutexReleased = TRUE;
  11771. if (ClientPacketType == http2coptD4_A6)
  11772. {
  11773. RpcStatus = ParseAndFreeD4_A6 (Buffer,
  11774. BufferLength,
  11775. fdClient,
  11776. &ProtocolVersion,
  11777. &ProxyConnectionTimeout
  11778. );
  11779. // we don't really do anything with ProxyConnectionTimeout. That's
  11780. // ok. It's there mostly for debugging.
  11781. }
  11782. else
  11783. {
  11784. RpcStatus = ParseAndFreeD5_A6 (Buffer,
  11785. BufferLength,
  11786. fdClient
  11787. );
  11788. }
  11789. BufferFreed = TRUE;
  11790. if (RpcStatus != RPC_S_OK)
  11791. {
  11792. AbortChannels(RpcStatus);
  11793. RpcStatus = RPC_P_PACKET_CONSUMED;
  11794. break;
  11795. }
  11796. if (ClientPacketType == http2coptD5_A6)
  11797. {
  11798. // in the D5 case, we won't send A11. Since
  11799. // some proxies are picky about sending all
  11800. // the declared data before allowing receiving
  11801. // data to come in, we need to send an empty packet
  11802. // of the necessary size to keep the proxy happy.
  11803. PingContext = AllocateAndInitializePingPacketWithSize (
  11804. GetD4_A11TotalLength()
  11805. );
  11806. if (PingContext == NULL)
  11807. {
  11808. AbortChannels(RPC_S_OUT_OF_MEMORY);
  11809. RpcStatus = RPC_P_PACKET_CONSUMED;
  11810. break;
  11811. }
  11812. RpcStatus = SendTrafficOnChannel(
  11813. &OutChannels[GetNonDefaultOutChannelSelector()],
  11814. PingContext
  11815. );
  11816. if (RpcStatus != RPC_S_OK)
  11817. {
  11818. FreeRTSPacket(PingContext);
  11819. AbortChannels(RpcStatus);
  11820. RpcStatus = RPC_P_PACKET_CONSUMED;
  11821. break;
  11822. }
  11823. }
  11824. D4_A7Context = AllocateAndInitializeD4_A7 (
  11825. fdServer,
  11826. &OutChannelCookies[GetNonDefaultOutChannelSelector()],
  11827. ProtocolVersion
  11828. );
  11829. if (D4_A7Context == NULL)
  11830. {
  11831. AbortChannels(RPC_S_OUT_OF_MEMORY);
  11832. RpcStatus = RPC_P_PACKET_CONSUMED;
  11833. break;
  11834. }
  11835. RpcStatus = SendTrafficOnDefaultChannel(TRUE, //IsInChannel
  11836. D4_A7Context
  11837. );
  11838. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  11839. TRUE // IsFromUpcall
  11840. );
  11841. if (RpcStatus != RPC_S_OK)
  11842. {
  11843. FreeRTSPacket(D4_A7Context);
  11844. AbortChannels(RpcStatus);
  11845. RpcStatus = RPC_P_PACKET_CONSUMED;
  11846. break;
  11847. }
  11848. RpcStatus = PostReceiveOnDefaultChannel (FALSE, // IsInChannel
  11849. http2ttRTS);
  11850. if (RpcStatus != RPC_S_OK)
  11851. AbortChannels(RpcStatus);
  11852. RpcStatus = RPC_P_PACKET_CONSUMED;
  11853. break;
  11854. case http2coptD4_A10:
  11855. case http2coptD5_B3:
  11856. // in channel can be in any opened state
  11857. if (ClientPacketType == http2coptD4_A10)
  11858. {
  11859. // out channel must be in http2svOpened_A10W
  11860. ASSERT(OutChannelState.State == http2svOpened_A10W);
  11861. if (OutChannelState.State != http2svOpened_A10W)
  11862. {
  11863. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11864. RpcStatus = RPC_P_PACKET_CONSUMED;
  11865. break;
  11866. }
  11867. InChannelState.Mutex.Clear();
  11868. MutexReleased = TRUE;
  11869. RpcStatus = ParseD4_A10 (Buffer,
  11870. BufferLength
  11871. );
  11872. if (RpcStatus != RPC_S_OK)
  11873. {
  11874. AbortChannels(RpcStatus);
  11875. RpcStatus = RPC_P_PACKET_CONSUMED;
  11876. break;
  11877. }
  11878. }
  11879. else
  11880. {
  11881. // out channel must be in http2svOpened_B3W
  11882. CORRUPTION_ASSERT(OutChannelState.State == http2svOpened_B3W);
  11883. if (OutChannelState.State != http2svOpened_B3W)
  11884. {
  11885. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11886. RpcStatus = RPC_P_PACKET_CONSUMED;
  11887. break;
  11888. }
  11889. InChannelState.Mutex.Clear();
  11890. MutexReleased = TRUE;
  11891. RpcStatus = ParseAndFreeD5_B3 (Buffer,
  11892. BufferLength
  11893. );
  11894. BufferFreed = TRUE;
  11895. if (RpcStatus != RPC_S_OK)
  11896. {
  11897. AbortChannels(RpcStatus);
  11898. RpcStatus = RPC_P_PACKET_CONSUMED;
  11899. break;
  11900. }
  11901. }
  11902. ChannelPtr = GetChannelPointerFromId(ChannelId);
  11903. OutChannel = (HTTP2ClientOutChannel *)ChannelPtr->LockChannelPointer();
  11904. if (OutChannel == NULL)
  11905. {
  11906. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11907. RpcStatus = RPC_P_PACKET_CONSUMED;
  11908. break;
  11909. }
  11910. NewChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  11911. OutChannel2 = (HTTP2ClientOutChannel *)NewChannelPtr->LockChannelPointer ();
  11912. if (OutChannel2 == NULL)
  11913. {
  11914. ChannelPtr->UnlockChannelPointer();
  11915. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11916. RpcStatus = RPC_P_PACKET_CONSUMED;
  11917. break;
  11918. }
  11919. OutChannel2->BlockDataReceives();
  11920. // we're done with this channel. We want to switch
  11921. // channels and destroy
  11922. // and detach the channel.
  11923. // In the D5 case we can't switch earlier, because we
  11924. // have a race condition where folks may receive data
  11925. // on the new channel before they have drained the old,
  11926. // which may result in out-of-order delivery. Since
  11927. // data receives are blocked here, switching and draining
  11928. // is atomical in respect to the new channel
  11929. SwitchDefaultOutChannelSelector();
  11930. // make sure everybody who was submitting is out
  11931. OutChannel->DrainPendingSubmissions();
  11932. // 1 is for the lock that we have
  11933. ChannelPtr->DrainPendingLocks(1);
  11934. RpcStatus = OutChannel->TransferReceiveStateToNewChannel(OutChannel2);
  11935. if (RpcStatus != RPC_S_OK)
  11936. {
  11937. OutChannel2->UnblockDataReceives();
  11938. NewChannelPtr->UnlockChannelPointer();
  11939. ChannelPtr->UnlockChannelPointer();
  11940. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  11941. RpcStatus = RPC_P_PACKET_CONSUMED;
  11942. break;
  11943. }
  11944. // if there is recv pending, but it is not an sync recv,
  11945. // make a note of that - we will resubmit it later. If it is
  11946. // sync, we will use the ReissueRecv mechanism to transfer
  11947. // the recv to the new channel
  11948. DataReceivePosted = FALSE;
  11949. if (OutChannel->IsDataReceivePosted())
  11950. {
  11951. if (OutChannel->IsSyncRecvPending())
  11952. {
  11953. // before we destroy, tell any pending recv to re-issue
  11954. // itself upon failure.
  11955. ReissueRecv = TRUE;
  11956. }
  11957. else
  11958. {
  11959. DataReceivePosted = TRUE;
  11960. }
  11961. }
  11962. ChannelPtr->UnlockChannelPointer();
  11963. if (ClientPacketType == http2coptD4_A10)
  11964. {
  11965. // after having transfered the receive settings,
  11966. // we can send D4/A11 to open the pipeline
  11967. RpcStatus = ForwardTrafficToDefaultChannel(FALSE, // IsInChannel
  11968. Buffer,
  11969. BufferLength
  11970. );
  11971. if (RpcStatus != RPC_S_OK)
  11972. {
  11973. NewChannelPtr->UnlockChannelPointer();
  11974. OutChannel2->UnblockDataReceives();
  11975. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11976. RpcStatus = RPC_P_PACKET_CONSUMED;
  11977. break;
  11978. }
  11979. // we no longer own the buffer
  11980. BufferFreed = TRUE;
  11981. }
  11982. // we couldn't unblock receives earlier because new receives
  11983. // must be synchronized w.r.t. D4/A11 - we can't post
  11984. // real receives before D4/A11 because it will switch WinHttp
  11985. // into receiveing mode. We also can't send D4/A11 before we
  11986. // have transferred the settings
  11987. OutChannel2->UnblockDataReceives();
  11988. NewChannelPtr->UnlockChannelPointer();
  11989. RpcStatus = PostReceiveOnDefaultChannel (FALSE, // IsInChannel
  11990. http2ttRTS);
  11991. if (RpcStatus != RPC_S_OK)
  11992. {
  11993. AbortChannels(RPC_S_PROTOCOL_ERROR);
  11994. RpcStatus = RPC_P_PACKET_CONSUMED;
  11995. break;
  11996. }
  11997. // detach, abort and free lifetime reference
  11998. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  11999. TRUE, // CalledFromUpcallContext
  12000. TRUE, // Abort
  12001. RPC_P_CONNECTION_SHUTDOWN
  12002. );
  12003. InChannelState.Mutex.Request();
  12004. // we haven't posted a receive yet - there is no
  12005. // way the state of the channel will change
  12006. if (ClientPacketType == http2coptD4_A10)
  12007. ExpectedState = http2svOpened_A10W;
  12008. else
  12009. ExpectedState = http2svOpened_B3W;
  12010. ASSERT(OutChannelState.State == ExpectedState);
  12011. // move channel state to opened
  12012. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  12013. OutChannelState.State = http2svOpened;
  12014. InChannelState.Mutex.Clear();
  12015. if (DataReceivePosted)
  12016. {
  12017. RpcStatus = PostReceiveOnDefaultChannel (
  12018. FALSE, // IsInChannel
  12019. http2ttData
  12020. );
  12021. if (RpcStatus != RPC_S_OK)
  12022. {
  12023. AbortChannels(RPC_S_PROTOCOL_ERROR);
  12024. }
  12025. }
  12026. RpcStatus = RPC_P_PACKET_CONSUMED;
  12027. break;
  12028. default:
  12029. ASSERT(0);
  12030. RpcStatus = RPC_S_INTERNAL_ERROR;
  12031. }
  12032. } // switch (InChannelState.State)
  12033. if (MutexReleased == FALSE)
  12034. {
  12035. InChannelState.Mutex.Clear();
  12036. }
  12037. } // if (IsRTSPacket(Buffer))
  12038. else
  12039. {
  12040. RpcStatus = RPC_S_OK;
  12041. // data packet - ownership of the buffer passes to the runtime
  12042. BufferFreed = TRUE;
  12043. }
  12044. } // else of clause if (EventStatus != RPC_S_OK)
  12045. } // else of clause if (IsInChannel(ChannelId))
  12046. CleanupAndExit:
  12047. if (((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_PACKET_CONSUMED))
  12048. || WakeOpenThread)
  12049. {
  12050. if ((InChannelState.State == http2svA3W)
  12051. || (InChannelState.State == http2svC2W)
  12052. || (InChannelState.State == http2svSearchProxy)
  12053. || WakeOpenThread
  12054. )
  12055. {
  12056. if (ClientOpenInEvent && (InOpenStatus != ERROR_IO_PENDING))
  12057. SetClientOpenInEvent();
  12058. else if (ClientOpenOutEvent && (OutOpenStatus != ERROR_IO_PENDING))
  12059. SetClientOpenOutEvent();
  12060. }
  12061. }
  12062. if (BufferFreed == FALSE)
  12063. RpcFreeBuffer(Buffer);
  12064. return RpcStatus;
  12065. }
  12066. RPC_STATUS HTTP2ClientVirtualConnection::SyncRecv (
  12067. IN BYTE **Buffer,
  12068. IN ULONG *BufferLength,
  12069. IN ULONG Timeout
  12070. )
  12071. /*++
  12072. Routine Description:
  12073. Do a sync receive on an HTTP connection.
  12074. Arguments:
  12075. Buffer - if successful, points to a buffer containing the next PDU.
  12076. BufferLength - if successful, contains the length of the message.
  12077. Timeout - the amount of time to wait for the receive. If -1, we wait
  12078. infinitely.
  12079. Return Value:
  12080. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  12081. --*/
  12082. {
  12083. HTTP2ChannelPointer *ChannelPtr;
  12084. HTTP2ClientChannel *Channel;
  12085. RPC_STATUS RpcStatus;
  12086. BOOL AbortNeeded;
  12087. BOOL IoPending;
  12088. while (TRUE)
  12089. {
  12090. Channel = LockDefaultOutChannel(&ChannelPtr);
  12091. if (Channel)
  12092. {
  12093. RpcStatus = Channel->SubmitSyncRecv(http2ttData);
  12094. // keep a reference for the operations below
  12095. Channel->AddReference();
  12096. ChannelPtr->UnlockChannelPointer();
  12097. IoPending = FALSE;
  12098. if (RpcStatus == RPC_S_OK)
  12099. {
  12100. AbortNeeded = FALSE;
  12101. RpcStatus = Channel->WaitForSyncRecv(Buffer,
  12102. BufferLength,
  12103. Timeout,
  12104. ConnectionTimeout,
  12105. this,
  12106. &AbortNeeded,
  12107. &IoPending
  12108. );
  12109. }
  12110. else
  12111. {
  12112. AbortNeeded = TRUE;
  12113. }
  12114. if (AbortNeeded)
  12115. {
  12116. Channel->Abort(RpcStatus);
  12117. }
  12118. if (IoPending)
  12119. {
  12120. Channel->WaitInfiniteForSyncReceive();
  12121. Channel->RemoveEvent();
  12122. }
  12123. if (AbortNeeded)
  12124. {
  12125. if (ReissueRecv)
  12126. {
  12127. ReissueRecv = FALSE;
  12128. // we don't re-issue on time outs
  12129. if (RpcStatus != RPC_S_CALL_CANCELLED)
  12130. {
  12131. Channel->RemoveReference();
  12132. continue;
  12133. }
  12134. }
  12135. else
  12136. {
  12137. // ASSERT(!"This test should not have failing receives\n");
  12138. }
  12139. }
  12140. Channel->RemoveReference();
  12141. if (RpcStatus == RPC_S_OK)
  12142. {
  12143. ASSERT(*Buffer != NULL);
  12144. ASSERT(IsBadWritePtr(*Buffer, 4) == FALSE);
  12145. }
  12146. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  12147. || (RpcStatus == RPC_P_SEND_FAILED)
  12148. || (RpcStatus == RPC_S_SERVER_UNAVAILABLE)
  12149. || (RpcStatus == RPC_P_CONNECTION_CLOSED) )
  12150. {
  12151. RpcStatus = RPC_P_RECEIVE_FAILED;
  12152. }
  12153. break;
  12154. }
  12155. else
  12156. {
  12157. RpcStatus = RPC_P_RECEIVE_FAILED;
  12158. break;
  12159. }
  12160. }
  12161. VALIDATE(RpcStatus)
  12162. {
  12163. RPC_S_OK,
  12164. RPC_S_OUT_OF_MEMORY,
  12165. RPC_S_OUT_OF_RESOURCES,
  12166. RPC_P_RECEIVE_FAILED,
  12167. RPC_S_CALL_CANCELLED,
  12168. RPC_P_SEND_FAILED,
  12169. RPC_P_CONNECTION_SHUTDOWN,
  12170. RPC_P_TIMEOUT
  12171. }
  12172. CORRUPTION_VALIDATE
  12173. {
  12174. RPC_S_PROTOCOL_ERROR
  12175. } CORRUPTION_END_VALIDATE;
  12176. return RpcStatus;
  12177. }
  12178. void HTTP2ClientVirtualConnection::Abort (
  12179. void
  12180. )
  12181. /*++
  12182. Routine Description:
  12183. Aborts an HTTP connection and disconnects the channels.
  12184. Must only come from the runtime.
  12185. Note: Don't call any virtual methods in this function. It
  12186. may be called in an environment without fully initialized
  12187. vtable.
  12188. Arguments:
  12189. Return Value:
  12190. --*/
  12191. {
  12192. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_CLIENT_VC, 0);
  12193. // abort the channels themselves
  12194. AbortChannels(RPC_P_CONNECTION_CLOSED);
  12195. // we got to the destructive phase of the abort
  12196. // guard against double aborts
  12197. if (Aborted.Increment() > 1)
  12198. return;
  12199. HTTP2VirtualConnection::DisconnectChannels(FALSE, 0);
  12200. // call destructor without freeing memory
  12201. HTTP2ClientVirtualConnection::~HTTP2ClientVirtualConnection();
  12202. }
  12203. void HTTP2ClientVirtualConnection::Close (
  12204. IN BOOL DontFlush
  12205. )
  12206. /*++
  12207. Routine Description:
  12208. Closes a client HTTP connection.
  12209. Note: Don't call virtual functions in this method.
  12210. It may be called in an environment without fully
  12211. initialized vtable.
  12212. Arguments:
  12213. DontFlush - non-zero if all buffers need to be flushed
  12214. before closing the connection. Zero otherwise.
  12215. Return Value:
  12216. --*/
  12217. {
  12218. HTTP2ClientVirtualConnection::Abort();
  12219. }
  12220. RPC_STATUS HTTP2ClientVirtualConnection::TurnOnOffKeepAlives (
  12221. IN BOOL TurnOn,
  12222. IN BOOL bProtectIO,
  12223. IN BOOL IsFromUpcall,
  12224. IN KEEPALIVE_TIMEOUT_UNITS Units,
  12225. IN OUT KEEPALIVE_TIMEOUT KATime,
  12226. IN ULONG KAInterval OPTIONAL
  12227. )
  12228. /*++
  12229. Routine Description:
  12230. Turns on keep alives for HTTP.
  12231. Arguments:
  12232. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  12233. are turned off.
  12234. bProtectIO - non-zero if IO needs to be protected against async close
  12235. of the connection.
  12236. IsFromUpcall - non-zero if called from upcall context. Zero otherwise.
  12237. Units - in what units is KATime
  12238. KATime - how much to wait before turning on keep alives
  12239. KAInterval - the interval between keep alives
  12240. Return Value:
  12241. RPC_S_OK or RPC_S_* / Win32 errors on failure
  12242. Note:
  12243. If we were to use it on the server, we must protect
  12244. the connection against async aborts.
  12245. Called in upcall or runtime context only.
  12246. --*/
  12247. {
  12248. HTTP2ClientInChannel *InChannel;
  12249. int i;
  12250. RPC_STATUS RpcStatus;
  12251. if (TurnOn)
  12252. CurrentKeepAlive = KAInterval;
  12253. else
  12254. CurrentKeepAlive = 0;
  12255. // convert the timeout from runtime scale to transport scale
  12256. if (Units == tuRuntime)
  12257. {
  12258. ASSERT(KATime.RuntimeUnits != RPC_C_BINDING_INFINITE_TIMEOUT);
  12259. KATime.Milliseconds = ConvertRuntimeTimeoutToWSTimeout(KATime.RuntimeUnits);
  12260. Units = tuMilliseconds;
  12261. }
  12262. // make the change on both channels
  12263. for (i = 0; i < 2; i ++)
  12264. {
  12265. InChannel = (HTTP2ClientInChannel *)InChannels[i].LockChannelPointer();
  12266. if (InChannel != NULL)
  12267. {
  12268. RpcStatus = InChannel->SetKeepAliveTimeout (
  12269. TurnOn,
  12270. bProtectIO,
  12271. Units,
  12272. KATime,
  12273. KATime.Milliseconds
  12274. );
  12275. InChannels[i].UnlockChannelPointer();
  12276. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  12277. IsFromUpcall
  12278. );
  12279. if (RpcStatus != RPC_S_OK)
  12280. break;
  12281. }
  12282. }
  12283. return RpcStatus;
  12284. }
  12285. RPC_STATUS HTTP2ClientVirtualConnection::RecycleChannel (
  12286. IN BOOL IsFromUpcall
  12287. )
  12288. /*++
  12289. Routine Description:
  12290. An in channel recycle is initiated. This may be called
  12291. in an upcall or runtime context.
  12292. Arguments:
  12293. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  12294. Return Value:
  12295. RPC_S_OK or other RPC_S_* errors for error
  12296. --*/
  12297. {
  12298. RPC_STATUS RpcStatus;
  12299. HTTP2ClientInChannel *NewInChannel;
  12300. int NonDefaultInChannelSelector;
  12301. HTTP2ChannelPointer *NewInChannelPtr;
  12302. HTTP2SendContext *D2_A1Context;
  12303. BOOL UseWinHttp;
  12304. #if DBG
  12305. DbgPrint("RPCRT4: %d Recycling IN channel\n", GetCurrentProcessId());
  12306. #endif
  12307. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  12308. // we shouldn't get recycle unless we're in an opened state
  12309. ASSERT(InChannelState.State == http2svOpened);
  12310. // create a new in channel
  12311. RpcStatus = ClientOpenInternal (&ConnectionHint,
  12312. TRUE, // HintWasInitialize
  12313. ConnectionTimeout,
  12314. DefaultReplacementChannelCallTimeout,
  12315. TRUE, // ClientOpenInChannel,
  12316. FALSE, // ClientOpenOutChannel
  12317. TRUE, // IsReplacementChannel
  12318. IsFromUpcall
  12319. );
  12320. if (RpcStatus != RPC_S_OK)
  12321. {
  12322. // ClientOpenInternal Aborts on failure. No need to abort
  12323. // here
  12324. return RpcStatus;
  12325. }
  12326. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  12327. NewInChannelPtr = &InChannels[NonDefaultInChannelSelector];
  12328. NewInChannel = (HTTP2ClientInChannel *)NewInChannelPtr->LockChannelPointer();
  12329. if (NewInChannel == NULL)
  12330. {
  12331. Abort();
  12332. return RPC_P_CONNECTION_SHUTDOWN;
  12333. }
  12334. InChannelState.Mutex.Request();
  12335. if (InChannelState.State != http2svOpened)
  12336. {
  12337. InChannelState.Mutex.Clear();
  12338. NewInChannelPtr->UnlockChannelPointer();
  12339. Abort();
  12340. return RPC_P_CONNECTION_SHUTDOWN;
  12341. }
  12342. // move to Opened_A4W in anticipation of the send we will make.
  12343. InChannelState.State = http2svOpened_A4W;
  12344. InChannelState.Mutex.Clear();
  12345. D2_A1Context = AllocateAndInitializeD2_A1(ProtocolVersion,
  12346. &EmbeddedConnectionCookie,
  12347. &InChannelCookies[DefaultInChannelSelector],
  12348. &InChannelCookies[NonDefaultInChannelSelector]
  12349. );
  12350. if (D2_A1Context == NULL)
  12351. {
  12352. NewInChannelPtr->UnlockChannelPointer();
  12353. Abort();
  12354. return RPC_S_OUT_OF_MEMORY;
  12355. }
  12356. RpcStatus = NewInChannel->Send(D2_A1Context);
  12357. if (RpcStatus != RPC_S_OK)
  12358. {
  12359. NewInChannelPtr->UnlockChannelPointer();
  12360. FreeRTSPacket(D2_A1Context);
  12361. Abort();
  12362. return RpcStatus;
  12363. }
  12364. if (!UseWinHttp)
  12365. {
  12366. RpcStatus = NewInChannel->Receive(http2ttRaw);
  12367. }
  12368. NewInChannelPtr->UnlockChannelPointer();
  12369. if (RpcStatus != RPC_S_OK)
  12370. {
  12371. Abort();
  12372. }
  12373. return RpcStatus;
  12374. }
  12375. RPC_STATUS HTTP2ClientVirtualConnection::OpenReplacementOutChannel (
  12376. void
  12377. )
  12378. /*++
  12379. Routine Description:
  12380. Opens a replacement out channel. Used during out channel
  12381. recycling.
  12382. Arguments:
  12383. Return Value:
  12384. RPC_S_OK or other RPC_S_* errors for error
  12385. --*/
  12386. {
  12387. RPC_STATUS RpcStatus;
  12388. HTTP2ClientOutChannel *NewOutChannel;
  12389. int NonDefaultOutChannelSelector;
  12390. HTTP2ChannelPointer *NewOutChannelPtr;
  12391. HTTP2SendContext *D4_A3Context;
  12392. KEEPALIVE_TIMEOUT KATime;
  12393. // create a new out channel
  12394. RpcStatus = ClientOpenInternal (&ConnectionHint,
  12395. TRUE, // HintWasInitialize
  12396. ConnectionTimeout,
  12397. DefaultReplacementChannelCallTimeout,
  12398. FALSE, // ClientOpenInChannel,
  12399. TRUE, // ClientOpenOutChannel
  12400. TRUE, // IsReplacementChannel
  12401. TRUE // IsFromUpcall
  12402. );
  12403. if (RpcStatus != RPC_S_OK)
  12404. {
  12405. // ClientOpenInternal has already aborted the connection
  12406. return RpcStatus;
  12407. }
  12408. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  12409. NewOutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  12410. NewOutChannel = (HTTP2ClientOutChannel *)NewOutChannelPtr->LockChannelPointer();
  12411. if (NewOutChannel == NULL)
  12412. {
  12413. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  12414. return RPC_P_CONNECTION_SHUTDOWN;
  12415. }
  12416. InChannelState.Mutex.Request();
  12417. if (OutChannelState.State != http2svOpened)
  12418. {
  12419. InChannelState.Mutex.Clear();
  12420. NewOutChannelPtr->UnlockChannelPointer();
  12421. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  12422. return RPC_P_CONNECTION_SHUTDOWN;
  12423. }
  12424. // move to Opened_A6W in anticipation of the send we will make.
  12425. OutChannelState.State = http2svOpened_A6W;
  12426. InChannelState.Mutex.Clear();
  12427. D4_A3Context = AllocateAndInitializeD4_A3(ProtocolVersion,
  12428. &EmbeddedConnectionCookie,
  12429. &OutChannelCookies[DefaultOutChannelSelector],
  12430. &OutChannelCookies[NonDefaultOutChannelSelector],
  12431. HTTP2ClientReceiveWindow
  12432. );
  12433. if (D4_A3Context == NULL)
  12434. {
  12435. NewOutChannelPtr->UnlockChannelPointer();
  12436. AbortChannels(RPC_S_OUT_OF_MEMORY);
  12437. return RPC_S_OUT_OF_MEMORY;
  12438. }
  12439. RpcStatus = NewOutChannel->Send(D4_A3Context);
  12440. if (RpcStatus != RPC_S_OK)
  12441. {
  12442. NewOutChannelPtr->UnlockChannelPointer();
  12443. FreeRTSPacket(D4_A3Context);
  12444. AbortChannels(RpcStatus);
  12445. return RpcStatus;
  12446. }
  12447. if (CurrentKeepAlive)
  12448. {
  12449. KATime.Milliseconds = 0;
  12450. RpcStatus = NewOutChannel->SetKeepAliveTimeout (
  12451. TRUE, // TurnOn
  12452. FALSE, // bProtectIO
  12453. tuMilliseconds,
  12454. KATime,
  12455. CurrentKeepAlive
  12456. );
  12457. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  12458. }
  12459. NewOutChannelPtr->UnlockChannelPointer();
  12460. if (RpcStatus != RPC_S_OK)
  12461. {
  12462. AbortChannels(RpcStatus);
  12463. }
  12464. return RpcStatus;
  12465. }
  12466. void HTTP2ClientVirtualConnection::AbortChannels (
  12467. IN RPC_STATUS RpcStatus
  12468. )
  12469. /*++
  12470. Routine Description:
  12471. Aborts an HTTP connection but does not disconnect
  12472. the channels. Can be called from above, upcall, or
  12473. neutral context, but not from submit context!
  12474. Arguments:
  12475. RpcStatus - the error to abort the channels with
  12476. Return Value:
  12477. --*/
  12478. {
  12479. // wait for the critical paths to unblock abort. The
  12480. // only critical path that will do that is Open, and
  12481. // it is extremely unlikely that this code will execute
  12482. // together with open (though it is possible, and this
  12483. // is why we need the additional synchronization).
  12484. ChannelsAborted = TRUE;
  12485. WaitForAbortsToUnblock();
  12486. HTTP2VirtualConnection::AbortChannels (RpcStatus);
  12487. }
  12488. HTTP2Channel *HTTP2ClientVirtualConnection::LockDefaultSendChannel (
  12489. OUT HTTP2ChannelPointer **ChannelPtr
  12490. )
  12491. /*++
  12492. Routine Description:
  12493. Locks the send channel. For client connections this is the in channel.
  12494. Arguments:
  12495. ChannelPtr - on success, the channel pointer to use.
  12496. Return Value:
  12497. The locked channel or NULL (same semantics as LockDefaultOutChannel)
  12498. --*/
  12499. {
  12500. return LockDefaultInChannel(ChannelPtr);
  12501. }
  12502. HTTP2Channel *HTTP2ClientVirtualConnection::LockDefaultReceiveChannel (
  12503. OUT HTTP2ChannelPointer **ChannelPtr
  12504. )
  12505. /*++
  12506. Routine Description:
  12507. Locks the receive channel. For client connections this is the out channel.
  12508. Arguments:
  12509. ChannelPtr - on success, the channel pointer to use.
  12510. Return Value:
  12511. The locked channel or NULL (same semantics as LockDefaultInChannel)
  12512. --*/
  12513. {
  12514. return LockDefaultOutChannel(ChannelPtr);
  12515. }
  12516. const int MaxOutChannelHeader = 300;
  12517. RPC_STATUS
  12518. RPC_ENTRY
  12519. HTTP2ClientReadChannelHeader (
  12520. IN WS_HTTP2_CONNECTION *Connection,
  12521. IN ULONG BytesRead,
  12522. OUT ULONG *NewBytesRead
  12523. )
  12524. /*++
  12525. Routine Description:
  12526. Read a channel HTTP header (usually some string). In success
  12527. case, there is real data in Connection->pReadBuffer. The
  12528. number of bytes there is in NewBytesRead
  12529. Arguments:
  12530. Connection - the connection on which the header arrived.
  12531. BytesRead - the bytes received from the net
  12532. NewBytesRead - the bytes read from the channel (success only)
  12533. Return Value:
  12534. RPC_S_OK or other RPC_S_* errors for error
  12535. --*/
  12536. {
  12537. DWORD message_size;
  12538. RPC_STATUS RpcStatus;
  12539. char *CurrentPosition;
  12540. char *LastPosition; // first position after end
  12541. char *LastPosition2; // first position after end + 4
  12542. // useful for end-of-loop comparison
  12543. char *StartPosition;
  12544. char *HeaderEnd; // first character after header end
  12545. ULONG HTTPResponse;
  12546. BYTE *NewBuffer;
  12547. BytesRead += Connection->iLastRead;
  12548. // we have read something. Let's process it now.
  12549. // search for double CR-LF (\r\n\r\n)
  12550. StartPosition = (char *)(Connection->pReadBuffer);
  12551. LastPosition = StartPosition + BytesRead;
  12552. LastPosition2 = LastPosition + 4;
  12553. HeaderEnd = NULL;
  12554. CurrentPosition = (char *)(Connection->pReadBuffer);
  12555. while (CurrentPosition < LastPosition2)
  12556. {
  12557. if ((*CurrentPosition == '\r')
  12558. && (*(CurrentPosition + 1) == '\n')
  12559. && (*(CurrentPosition + 2) == '\r')
  12560. && (*(CurrentPosition + 3) == '\n')
  12561. )
  12562. {
  12563. // we have a full header
  12564. HeaderEnd = CurrentPosition + 4;
  12565. break;
  12566. }
  12567. CurrentPosition ++;
  12568. }
  12569. if (CurrentPosition - StartPosition >= MaxOutChannelHeader)
  12570. {
  12571. // we should have seen the header by now. Abort. Returning
  12572. // failure is enough - we know the caller will abort
  12573. return RPC_S_PROTOCOL_ERROR;
  12574. }
  12575. if (HeaderEnd == NULL)
  12576. {
  12577. // we didn't find the end of the header. Submit another receive
  12578. // for the rest
  12579. RpcStatus = TransConnectionReallocPacket(Connection,
  12580. &Connection->pReadBuffer,
  12581. BytesRead,
  12582. MaxOutChannelHeader);
  12583. if (RpcStatus != RPC_S_OK)
  12584. {
  12585. ASSERT(RpcStatus == RPC_S_OUT_OF_MEMORY);
  12586. return(RpcStatus);
  12587. }
  12588. Connection->iLastRead = BytesRead;
  12589. Connection->maxReadBuffer = MaxOutChannelHeader;
  12590. return RPC_P_PARTIAL_RECEIVE;
  12591. }
  12592. // we have found the header end. Grab the status code
  12593. HTTPResponse = HttpParseResponse(StartPosition);
  12594. if ((HTTPResponse >= RPC_S_INVALID_STRING_BINDING) && (HTTPResponse <= RPC_X_BAD_STUB_DATA))
  12595. {
  12596. // if it is an RPC error code, just return it.
  12597. return HTTPResponse;
  12598. }
  12599. if (HTTPResponse != 200)
  12600. return RPC_S_PROTOCOL_ERROR;
  12601. // check whether we have something else besides the HTTP header
  12602. if (HeaderEnd < LastPosition)
  12603. {
  12604. NewBuffer = TransConnectionAllocatePacket(Connection,
  12605. LastPosition - HeaderEnd);
  12606. if (0 == NewBuffer)
  12607. return RPC_S_OUT_OF_MEMORY;
  12608. RpcpMemoryCopy(NewBuffer, HeaderEnd, LastPosition - HeaderEnd);
  12609. *NewBytesRead = LastPosition - HeaderEnd;
  12610. RpcFreeBuffer(Connection->pReadBuffer);
  12611. Connection->pReadBuffer = NewBuffer;
  12612. Connection->maxReadBuffer = LastPosition - HeaderEnd;
  12613. Connection->iLastRead = 0;
  12614. Connection->HeaderRead = TRUE;
  12615. return RPC_S_OK;
  12616. }
  12617. // reset the pointer. By doing so we forget all we have
  12618. // read so far (which is only the HTTP header anyway)
  12619. Connection->iLastRead = 0;
  12620. Connection->HeaderRead = TRUE;
  12621. return RPC_P_PARTIAL_RECEIVE;
  12622. }
  12623. // this is a bit mask. For any particular scheme, AND it with the constant
  12624. // Non-zero means it is multillegged. Schemes are:
  12625. // Scheme Value Multilegged
  12626. // RPC_C_HTTP_AUTHN_SCHEME_BASIC 0x00000001 0
  12627. // RPC_C_HTTP_AUTHN_SCHEME_NTLM 0x00000002 1
  12628. // RPC_C_HTTP_AUTHN_SCHEME_PASSPORT 0x00000004 1
  12629. // RPC_C_HTTP_AUTHN_SCHEME_DIGEST 0x00000008 1
  12630. // RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE 0x00000010 1
  12631. const ULONG MultiLeggedSchemeMap =
  12632. RPC_C_HTTP_AUTHN_SCHEME_NTLM
  12633. | RPC_C_HTTP_AUTHN_SCHEME_PASSPORT
  12634. | RPC_C_HTTP_AUTHN_SCHEME_DIGEST
  12635. | RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE;
  12636. /*
  12637. All client opened types are valid initial states. The transitions are:
  12638. cotSearchProxy ------+----> cotUknownAuth
  12639. |
  12640. +----------------+---------------+
  12641. | | |
  12642. cotMLAuth cotSLAuth cotNoAuth
  12643. |
  12644. cotMLAuth2
  12645. */
  12646. typedef enum tagClientOpenTypes
  12647. {
  12648. cotSearchProxy,
  12649. cotNoAuth,
  12650. cotMLAuth,
  12651. cotMLAuth2,
  12652. cotSLAuth,
  12653. cotUnknownAuth,
  12654. cotInvalid
  12655. } ClientOpenTypes;
  12656. const char *InHeaderVerb = "RPC_IN_DATA";
  12657. const int InHeaderVerbLength = 11; // length of RPC_IN_DATA
  12658. const char *OutHeaderVerb = "RPC_OUT_DATA";
  12659. const int OutHeaderVerbLength = 12; // length of RPC_OUT_DATA
  12660. const BYTE EchoData[4] = {0xF8, 0xE8, 0x18, 0x08};
  12661. const ULONG EchoDataLength = sizeof(EchoData);
  12662. RPC_STATUS HTTP2ClientVirtualConnection::ClientOpenInternal (
  12663. IN HTTPResolverHint *Hint,
  12664. IN BOOL HintWasInitialized,
  12665. IN UINT ConnTimeout,
  12666. IN ULONG CallTimeout,
  12667. IN BOOL ClientOpenInChannel,
  12668. IN BOOL ClientOpenOutChannel,
  12669. IN BOOL IsReplacementChannel,
  12670. IN BOOL IsFromUpcall
  12671. )
  12672. /*++
  12673. Routine Description:
  12674. Opens a client side virtual connection.
  12675. Arguments:
  12676. Hint - the resolver hint
  12677. HintWasInitialized - the hint was initialized on input.
  12678. ConnTimeout - connection timeout
  12679. CallTimeout - operation timeout
  12680. ClientOpenInChannel - non-zero if the in channel is to be opened.
  12681. ClientOpenOutChannel - non-zero if the out channel is to be
  12682. opened.
  12683. IsReplacementChannel - non-zero if this is channel recycling
  12684. IsFromUpcall - non-zero if this is called from an upcall. Zero otherwise.
  12685. Return Value:
  12686. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  12687. --*/
  12688. {
  12689. RPC_STATUS RpcStatus;
  12690. HTTP2ClientInChannel *NewInChannel;
  12691. HTTP2ClientOutChannel *NewOutChannel;
  12692. BOOL InChannelLocked = FALSE;
  12693. BOOL OutChannelLocked = FALSE;
  12694. HTTP2SendContext *OutChannelSendContext = NULL;
  12695. HTTP2SendContext *InChannelSendContext = NULL;
  12696. ULONG WaitResult;
  12697. HANDLE LocalClientOpenEvent;
  12698. BOOL UseWinHttp;
  12699. KEEPALIVE_TIMEOUT KATimeout;
  12700. BOOL RebuildInChannel;
  12701. BOOL RebuildOutChannel;
  12702. BOOL NukeInChannel;
  12703. BOOL NukeOutChannel;
  12704. BOOL ResetInChannel;
  12705. BOOL ResetOutChannel;
  12706. BOOL SendInChannel;
  12707. BOOL SendOutChannel;
  12708. BOOL OpenInChannel;
  12709. BOOL OpenOutChannel;
  12710. BOOL ReceiveInChannel;
  12711. BOOL ReceiveOutChannel;
  12712. RPCProxyAccessType StoredAccessType;
  12713. const char *VerbToUse;
  12714. int VerbLengthToUse;
  12715. const BYTE *AdditionalDataToUse;
  12716. ULONG AdditionalDataLengthToUse;
  12717. HTTP2StateValues NewConnectionState = http2svInvalid;
  12718. BOOL SetNewConnectionState;
  12719. RPC_STATUS LocalInOpenStatus;
  12720. RPC_STATUS LocalOutOpenStatus;
  12721. ULONG InChosenAuthScheme;
  12722. ULONG OutChosenAuthScheme;
  12723. BOOL IsKeepAlive;
  12724. BOOL IsDone;
  12725. int NonDefaultInChannelSelector;
  12726. int NonDefaultOutChannelSelector;
  12727. HTTP2ChannelPointer *InChannelPtr;
  12728. HTTP2ChannelPointer *OutChannelPtr;
  12729. ClientOpenTypes InOpenType;
  12730. ClientOpenTypes OutOpenType;
  12731. ClientOpenTypes OldOpenType;
  12732. ClientOpenTypes OldInOpenType;
  12733. ClientOpenTypes OldOutOpenType;
  12734. int CurrentCase;
  12735. #if DBG
  12736. int NumberOfRetries = 0;
  12737. #endif
  12738. BOOL AbortsBlocked = FALSE; // if non-zero, the aborts have been blocked and need
  12739. // unblocking before we exit
  12740. if (IsReplacementChannel == FALSE)
  12741. {
  12742. if (ConnTimeout != RPC_C_BINDING_INFINITE_TIMEOUT)
  12743. {
  12744. ASSERT( ((long)ConnTimeout >= RPC_C_BINDING_MIN_TIMEOUT)
  12745. && (ConnTimeout <= RPC_C_BINDING_MAX_TIMEOUT));
  12746. // convert the timeout from runtime scale to transport scale
  12747. ConnectionTimeout = ConvertRuntimeTimeoutToWSTimeout(ConnTimeout);
  12748. }
  12749. else
  12750. {
  12751. ConnectionTimeout = INFINITE;
  12752. }
  12753. }
  12754. UseWinHttp = ShouldUseWinHttp(HttpCredentials);
  12755. if (UseWinHttp)
  12756. {
  12757. RpcStatus = InitWinHttpIfNecessary();
  12758. if (RpcStatus != RPC_S_OK)
  12759. return RpcStatus;
  12760. }
  12761. InOpenType = OutOpenType = cotInvalid;
  12762. InChosenAuthScheme = 0;
  12763. OutChosenAuthScheme = 0;
  12764. IsDone = FALSE;
  12765. if (HttpCredentials)
  12766. {
  12767. // WinHttp5.x does not support pre-auth for digest. This means that even if
  12768. // you know that digest is your scheme, you have to pretend that you don't
  12769. // and wait for the challenge before you choose it. Otherwise WinHttp5.x will
  12770. // complain and fail.
  12771. if ((HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME)
  12772. && (*(HttpCredentials->AuthnSchemes) != RPC_C_HTTP_AUTHN_SCHEME_DIGEST))
  12773. {
  12774. OutChosenAuthScheme = InChosenAuthScheme = *(HttpCredentials->AuthnSchemes);
  12775. if (ClientOpenInChannel)
  12776. {
  12777. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  12778. InOpenType = cotMLAuth;
  12779. else
  12780. InOpenType = cotSLAuth;
  12781. }
  12782. if (ClientOpenOutChannel)
  12783. {
  12784. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  12785. OutOpenType = cotMLAuth;
  12786. else
  12787. OutOpenType = cotSLAuth;
  12788. }
  12789. }
  12790. }
  12791. else if (IsReplacementChannel == FALSE)
  12792. {
  12793. ASSERT(OutOpenType == cotInvalid);
  12794. InOpenType = OutOpenType = cotNoAuth;
  12795. }
  12796. else if (ClientOpenInChannel)
  12797. {
  12798. InOpenType = cotNoAuth;
  12799. IsDone = TRUE;
  12800. }
  12801. else
  12802. {
  12803. OutOpenType = cotNoAuth;
  12804. IsDone = TRUE;
  12805. }
  12806. LocalClientOpenEvent = CreateEvent(NULL, // lpEventAttributes
  12807. FALSE, // bManualReset
  12808. FALSE, // bInitialState
  12809. NULL // lpName
  12810. );
  12811. if (LocalClientOpenEvent == NULL)
  12812. return RPC_S_OUT_OF_MEMORY;
  12813. if (IsReplacementChannel == FALSE)
  12814. {
  12815. RpcStatus = EmbeddedConnectionCookie.Create();
  12816. if (RpcStatus != RPC_S_OK)
  12817. goto AbortAndExit;
  12818. }
  12819. else
  12820. {
  12821. if (ClientOpenInChannel)
  12822. NonDefaultInChannelSelector = GetNonDefaultInChannelSelector();
  12823. else
  12824. {
  12825. ASSERT(ClientOpenOutChannel);
  12826. NonDefaultOutChannelSelector = GetNonDefaultOutChannelSelector();
  12827. }
  12828. }
  12829. if (ClientOpenInChannel)
  12830. {
  12831. if (IsReplacementChannel)
  12832. RpcStatus = InChannelCookies[NonDefaultInChannelSelector].Create();
  12833. else
  12834. RpcStatus = InChannelCookies[0].Create();
  12835. if (RpcStatus != RPC_S_OK)
  12836. goto AbortAndExit;
  12837. }
  12838. if (ClientOpenOutChannel)
  12839. {
  12840. if (IsReplacementChannel)
  12841. RpcStatus = OutChannelCookies[NonDefaultOutChannelSelector].Create();
  12842. else
  12843. RpcStatus = OutChannelCookies[0].Create();
  12844. if (RpcStatus != RPC_S_OK)
  12845. goto AbortAndExit;
  12846. }
  12847. if (ClientOpenInChannel)
  12848. {
  12849. RebuildInChannel = TRUE;
  12850. NukeInChannel = FALSE;
  12851. ResetInChannel = FALSE;
  12852. OpenInChannel = TRUE;
  12853. InOpenStatus = ERROR_IO_PENDING;
  12854. }
  12855. else
  12856. {
  12857. RebuildInChannel = FALSE;
  12858. NukeInChannel = FALSE;
  12859. ResetInChannel = FALSE;
  12860. OpenInChannel = FALSE;
  12861. ReceiveInChannel = FALSE;
  12862. }
  12863. if (ClientOpenOutChannel)
  12864. {
  12865. RebuildOutChannel = TRUE;
  12866. NukeOutChannel = FALSE;
  12867. ResetOutChannel = FALSE;
  12868. OpenOutChannel = TRUE;
  12869. // receive is done below
  12870. OutOpenStatus = ERROR_IO_PENDING;
  12871. }
  12872. else
  12873. {
  12874. RebuildOutChannel = FALSE;
  12875. NukeOutChannel = FALSE;
  12876. ResetOutChannel = FALSE;
  12877. OpenOutChannel = FALSE;
  12878. ReceiveOutChannel = FALSE;
  12879. }
  12880. SetNewConnectionState = FALSE;
  12881. ClientOpenInEvent = ClientOpenOutEvent = LocalClientOpenEvent;
  12882. ASSERT(InChosenAuthScheme == OutChosenAuthScheme);
  12883. // do we know whether to use a proxy?
  12884. StoredAccessType = Hint->AccessType;
  12885. if (StoredAccessType == rpcpatUnknown)
  12886. {
  12887. // this should never happen for replacement channels
  12888. ASSERT(IsReplacementChannel == FALSE);
  12889. // we don't.
  12890. InOpenType = OutOpenType = cotSearchProxy;
  12891. // move to http2svSearchProxy
  12892. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svSearchProxy, 1, 0);
  12893. InChannelState.State = http2svSearchProxy;
  12894. SendInChannel = FALSE;
  12895. SendOutChannel = FALSE;
  12896. ReceiveInChannel = TRUE;
  12897. ReceiveOutChannel = TRUE;
  12898. }
  12899. else
  12900. {
  12901. // we know. Do we know what authentication to use?
  12902. if (InChosenAuthScheme)
  12903. {
  12904. ASSERT(InChosenAuthScheme == OutChosenAuthScheme);
  12905. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  12906. {
  12907. if (ClientOpenInChannel)
  12908. InOpenType = cotMLAuth;
  12909. else
  12910. InOpenType = cotInvalid;
  12911. if (ClientOpenOutChannel)
  12912. {
  12913. OutOpenType = cotMLAuth;
  12914. ReceiveOutChannel = TRUE;
  12915. }
  12916. else
  12917. {
  12918. OutOpenType = cotInvalid;
  12919. ReceiveOutChannel = FALSE;
  12920. }
  12921. }
  12922. else
  12923. {
  12924. if (ClientOpenInChannel)
  12925. {
  12926. InOpenType = cotSLAuth;
  12927. if (IsReplacementChannel)
  12928. IsDone = TRUE;
  12929. }
  12930. else
  12931. InOpenType = cotInvalid;
  12932. if (ClientOpenOutChannel)
  12933. {
  12934. OutOpenType = cotSLAuth;
  12935. if (IsReplacementChannel)
  12936. {
  12937. ReceiveOutChannel = FALSE;
  12938. IsDone = TRUE;
  12939. }
  12940. else
  12941. ReceiveOutChannel = TRUE;
  12942. }
  12943. else
  12944. {
  12945. OutOpenType = cotInvalid;
  12946. ReceiveOutChannel = FALSE;
  12947. }
  12948. }
  12949. }
  12950. else
  12951. {
  12952. if (ClientOpenInChannel)
  12953. {
  12954. if (InOpenType != cotNoAuth)
  12955. InOpenType = cotUnknownAuth;
  12956. }
  12957. else
  12958. InOpenType = cotInvalid;
  12959. if (ClientOpenOutChannel)
  12960. {
  12961. if (OutOpenType != cotNoAuth)
  12962. {
  12963. OutOpenType = cotUnknownAuth;
  12964. ReceiveOutChannel = TRUE;
  12965. }
  12966. else if (IsReplacementChannel)
  12967. ReceiveOutChannel = FALSE;
  12968. else
  12969. ReceiveOutChannel = TRUE;
  12970. }
  12971. else
  12972. {
  12973. OutOpenType = cotInvalid;
  12974. ReceiveOutChannel = FALSE;
  12975. }
  12976. }
  12977. if (IsReplacementChannel == FALSE)
  12978. {
  12979. // move to http2svA3W
  12980. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svA3W, 1, 0);
  12981. InChannelState.State = http2svA3W;
  12982. }
  12983. if (
  12984. (
  12985. (InOpenType == cotSLAuth)
  12986. ||
  12987. (InOpenType == cotNoAuth)
  12988. )
  12989. &&
  12990. (IsReplacementChannel == FALSE)
  12991. )
  12992. {
  12993. SendInChannel = TRUE;
  12994. }
  12995. else
  12996. SendInChannel = FALSE;
  12997. if (
  12998. (
  12999. (OutOpenType == cotSLAuth)
  13000. ||
  13001. (OutOpenType == cotNoAuth)
  13002. )
  13003. &&
  13004. (IsReplacementChannel == FALSE)
  13005. )
  13006. {
  13007. SendOutChannel = TRUE;
  13008. }
  13009. else
  13010. SendOutChannel = FALSE;
  13011. // 3 cases for the receive on the in channel
  13012. // 1. If we don't use WinHttp and this is the first open or is in channel replacement,
  13013. // we post a receive on this channel
  13014. // 2. If this is a single legged operation, or this is a replacement channel we don't
  13015. // post a receive.
  13016. // 3. All other cases (we use WinHttp and this is MLAuth/UnknownAuth) we post a receive
  13017. if (ClientOpenInChannel)
  13018. {
  13019. if (!UseWinHttp)
  13020. ReceiveInChannel = TRUE;
  13021. else if ((InOpenType == cotNoAuth) || (InOpenType == cotSLAuth))
  13022. ReceiveInChannel = FALSE;
  13023. else
  13024. ReceiveInChannel = TRUE;
  13025. }
  13026. else
  13027. ReceiveInChannel = FALSE;
  13028. }
  13029. while (TRUE)
  13030. {
  13031. #if DBG_ERROR
  13032. DbgPrint("Starting loop iteration ....\n");
  13033. NumberOfRetries ++;
  13034. ASSERT (NumberOfRetries < 10);
  13035. #endif
  13036. if (ClientOpenInChannel == FALSE)
  13037. {
  13038. // if we were told not to touch the in channel, make
  13039. // sure we don't
  13040. ASSERT(RebuildInChannel == FALSE
  13041. && NukeInChannel == FALSE
  13042. && ResetInChannel == FALSE
  13043. && SendInChannel == FALSE
  13044. && OpenInChannel == FALSE
  13045. && ReceiveInChannel == FALSE);
  13046. }
  13047. if (ClientOpenOutChannel == FALSE)
  13048. {
  13049. // if we were told not to touch the out channel, make
  13050. // sure we don't
  13051. ASSERT(RebuildOutChannel == FALSE
  13052. && NukeOutChannel == FALSE
  13053. && ResetOutChannel == FALSE
  13054. && SendOutChannel == FALSE
  13055. && OpenOutChannel == FALSE
  13056. && ReceiveOutChannel == FALSE);
  13057. }
  13058. if (NukeInChannel)
  13059. {
  13060. if (IsReplacementChannel)
  13061. InChannelPtr = &InChannels[NonDefaultInChannelSelector];
  13062. else
  13063. InChannelPtr = &InChannels[0];
  13064. InChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  13065. IsReplacementChannel, // CalledFromUpcallContext
  13066. TRUE, // Abort
  13067. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  13068. );
  13069. InOpenStatus = ERROR_IO_PENDING;
  13070. }
  13071. if (NukeOutChannel)
  13072. {
  13073. if (IsReplacementChannel)
  13074. OutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  13075. else
  13076. OutChannelPtr = &OutChannels[0];
  13077. OutChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  13078. IsReplacementChannel, // CalledFromUpcallContext
  13079. TRUE, // Abort
  13080. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  13081. );
  13082. OutOpenStatus = ERROR_IO_PENDING;
  13083. }
  13084. // after both channels are nuked, see whether we need to change the
  13085. // connection state. We have to do this after nuking the channels
  13086. // to avoid a race in ReceiveComplete where late receives may
  13087. // see a different state
  13088. if (SetNewConnectionState)
  13089. {
  13090. ASSERT(NewConnectionState != http2svInvalid);
  13091. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, NewConnectionState, 1, 0);
  13092. InChannelState.State = NewConnectionState;
  13093. SetNewConnectionState = FALSE;
  13094. }
  13095. // we're entering the critical path of opening - the creating of the channel
  13096. // and the opening itself. Block aborts until we fully open both channels
  13097. // (or fail to do so)
  13098. RpcStatus = BlockAborts();
  13099. if (RpcStatus != RPC_S_OK)
  13100. {
  13101. goto AbortAndExit;
  13102. }
  13103. AbortsBlocked = TRUE;
  13104. if (RebuildInChannel)
  13105. {
  13106. if (StoredAccessType == rpcpatUnknown)
  13107. {
  13108. ASSERT((InOpenType == cotSearchProxy)
  13109. || (InOpenType == cotMLAuth)
  13110. || (InOpenType == cotSLAuth)
  13111. );
  13112. // if we don't know the type yet, try
  13113. // direct for the in, proxy for the out.
  13114. // One of them will work.
  13115. Hint->AccessType = rpcpatDirect;
  13116. }
  13117. // initialize in channel
  13118. RpcStatus = AllocateAndInitializeInChannel(Hint,
  13119. HintWasInitialized,
  13120. CallTimeout,
  13121. UseWinHttp,
  13122. &NewInChannel
  13123. );
  13124. // restore the access type
  13125. if (StoredAccessType == rpcpatUnknown)
  13126. {
  13127. Hint->AccessType = StoredAccessType;
  13128. }
  13129. if (RpcStatus != RPC_S_OK)
  13130. {
  13131. goto AbortAndExit;
  13132. }
  13133. if (IsReplacementChannel)
  13134. SetNonDefaultInChannel(NewInChannel);
  13135. else
  13136. SetFirstInChannel(NewInChannel);
  13137. }
  13138. if (RebuildOutChannel)
  13139. {
  13140. if (StoredAccessType == rpcpatUnknown)
  13141. {
  13142. ASSERT((OutOpenType == cotSearchProxy)
  13143. || (OutOpenType == cotMLAuth)
  13144. || (OutOpenType == cotSLAuth)
  13145. );
  13146. // if we don't know the type yet, try
  13147. // direct for the in, proxy for the out.
  13148. // One of them will work.
  13149. Hint->AccessType = rpcpatHTTPProxy;
  13150. }
  13151. // initialize out channel
  13152. RpcStatus = AllocateAndInitializeOutChannel(Hint,
  13153. TRUE, // HintWasInitialized
  13154. CallTimeout,
  13155. UseWinHttp,
  13156. &NewOutChannel
  13157. );
  13158. // restore the access type
  13159. if (StoredAccessType == rpcpatUnknown)
  13160. {
  13161. Hint->AccessType = StoredAccessType;
  13162. }
  13163. if (RpcStatus != RPC_S_OK)
  13164. {
  13165. goto AbortAndExit;
  13166. }
  13167. if (IsReplacementChannel)
  13168. SetNonDefaultOutChannel(NewOutChannel);
  13169. else
  13170. SetFirstOutChannel(NewOutChannel);
  13171. }
  13172. // at least one channel must wait for something to happen
  13173. if (IsReplacementChannel == FALSE)
  13174. {
  13175. ASSERT((InOpenStatus == ERROR_IO_PENDING)
  13176. || (OutOpenStatus == ERROR_IO_PENDING));
  13177. }
  13178. else if (ClientOpenInChannel)
  13179. {
  13180. ASSERT(InOpenStatus == ERROR_IO_PENDING);
  13181. }
  13182. else
  13183. {
  13184. ASSERT(ClientOpenOutChannel);
  13185. ASSERT(OutOpenStatus == ERROR_IO_PENDING);
  13186. }
  13187. if (ResetInChannel || OpenInChannel || SendInChannel)
  13188. {
  13189. // Lock channel
  13190. // after calling ClientOpen, we may be aborted asynchronously at any moment.
  13191. // we will have pending async operations soon. Do the channel access by the
  13192. // book.
  13193. if (IsReplacementChannel)
  13194. InChannelPtr = &InChannels[NonDefaultInChannelSelector];
  13195. else
  13196. InChannelPtr = &InChannels[0];
  13197. NewInChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  13198. if (NewInChannel == NULL)
  13199. {
  13200. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  13201. goto AbortAndExit;
  13202. }
  13203. InChannelLocked = TRUE;
  13204. }
  13205. // Nuke and rebuild are mutually exclusive with Reset
  13206. if (ResetInChannel)
  13207. {
  13208. ASSERT(NukeInChannel == FALSE);
  13209. ASSERT(RebuildInChannel == FALSE);
  13210. NewInChannel->Reset();
  13211. }
  13212. if (OpenInChannel)
  13213. {
  13214. // do we do in_data or echo's?
  13215. if ((InOpenType == cotSearchProxy)
  13216. || (InOpenType == cotMLAuth)
  13217. || (InOpenType == cotUnknownAuth)
  13218. )
  13219. {
  13220. AdditionalDataToUse = EchoData;
  13221. AdditionalDataLengthToUse = EchoDataLength;
  13222. if (StoredAccessType == rpcpatUnknown)
  13223. {
  13224. // if we don't know the type yet, try
  13225. // direct for the in, proxy for the out.
  13226. // One of them will work.
  13227. Hint->AccessType = rpcpatDirect;
  13228. }
  13229. }
  13230. else
  13231. {
  13232. ASSERT((InOpenType == cotSLAuth)
  13233. || (InOpenType == cotNoAuth)
  13234. || (InOpenType == cotMLAuth2)
  13235. );
  13236. ASSERT(StoredAccessType != rpcpatUnknown);
  13237. if (IsReplacementChannel == FALSE)
  13238. {
  13239. ASSERT(SendInChannel);
  13240. }
  13241. else
  13242. {
  13243. ASSERT(SendInChannel == FALSE);
  13244. }
  13245. AdditionalDataToUse = NULL;
  13246. AdditionalDataLengthToUse = 0;
  13247. }
  13248. if (IsReplacementChannel == FALSE)
  13249. {
  13250. RpcStatus = NewInChannel->Unplug();
  13251. // since no sends have been done yet, unplugging cannot fail here
  13252. ASSERT(RpcStatus == RPC_S_OK);
  13253. }
  13254. RpcStatus = NewInChannel->ClientOpen(Hint,
  13255. InHeaderVerb,
  13256. InHeaderVerbLength,
  13257. UseWinHttp,
  13258. HttpCredentials,
  13259. InChosenAuthScheme,
  13260. CallTimeout,
  13261. AdditionalDataToUse,
  13262. AdditionalDataLengthToUse
  13263. );
  13264. // restore the access type
  13265. if (StoredAccessType == rpcpatUnknown)
  13266. {
  13267. Hint->AccessType = StoredAccessType;
  13268. }
  13269. if (RpcStatus != RPC_S_OK)
  13270. {
  13271. // if we are searching for the proxy, a failure here is not
  13272. // fatal. We'll just prevent further operations on the channel,
  13273. // and see what the other channel has to say
  13274. if (InChannelState.State == http2svSearchProxy)
  13275. {
  13276. InOpenStatus = RpcStatus;
  13277. SendInChannel = FALSE;
  13278. ReceiveInChannel = FALSE;
  13279. // we don't need to unlock the channel - the code
  13280. // below will do.
  13281. }
  13282. else
  13283. goto AbortAndExit;
  13284. }
  13285. }
  13286. if (ResetOutChannel || OpenOutChannel || SendOutChannel)
  13287. {
  13288. if (IsReplacementChannel)
  13289. OutChannelPtr = &OutChannels[NonDefaultOutChannelSelector];
  13290. else
  13291. OutChannelPtr = &OutChannels[0];
  13292. NewOutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  13293. if (NewOutChannel == NULL)
  13294. {
  13295. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  13296. goto AbortAndExit;
  13297. }
  13298. OutChannelLocked = TRUE;
  13299. }
  13300. // Nuke and rebuild are mutually exclusive with Reset
  13301. if (ResetOutChannel)
  13302. {
  13303. ASSERT(NukeOutChannel == FALSE);
  13304. ASSERT(RebuildOutChannel == FALSE);
  13305. NewOutChannel->Reset();
  13306. }
  13307. if (OpenOutChannel)
  13308. {
  13309. // do we do out_data or echo's?
  13310. if ((OutOpenType == cotSearchProxy)
  13311. || (OutOpenType == cotMLAuth)
  13312. || (OutOpenType == cotUnknownAuth)
  13313. )
  13314. {
  13315. AdditionalDataToUse = EchoData;
  13316. AdditionalDataLengthToUse = 0;
  13317. AdditionalDataLengthToUse = EchoDataLength;
  13318. if (StoredAccessType == rpcpatUnknown)
  13319. {
  13320. // if we don't know the type yet, try
  13321. // direct for the in, proxy for the out.
  13322. // One of them will work.
  13323. Hint->AccessType = rpcpatHTTPProxy;
  13324. }
  13325. }
  13326. else
  13327. {
  13328. ASSERT((OutOpenType == cotNoAuth)
  13329. || (OutOpenType == cotSLAuth)
  13330. || (OutOpenType == cotMLAuth2)
  13331. );
  13332. ASSERT(StoredAccessType != rpcpatUnknown);
  13333. if (IsReplacementChannel == FALSE)
  13334. {
  13335. ASSERT(SendOutChannel);
  13336. }
  13337. else
  13338. {
  13339. ASSERT(SendOutChannel == FALSE);
  13340. }
  13341. AdditionalDataToUse = NULL;
  13342. AdditionalDataLengthToUse = 0;
  13343. }
  13344. RpcStatus = NewOutChannel->ClientOpen(Hint,
  13345. OutHeaderVerb,
  13346. OutHeaderVerbLength,
  13347. IsReplacementChannel, // ReplacementChannel
  13348. UseWinHttp,
  13349. HttpCredentials,
  13350. OutChosenAuthScheme,
  13351. CallTimeout,
  13352. AdditionalDataToUse,
  13353. AdditionalDataLengthToUse
  13354. );
  13355. // restore the access type
  13356. if (StoredAccessType == rpcpatUnknown)
  13357. {
  13358. Hint->AccessType = StoredAccessType;
  13359. }
  13360. if (RpcStatus != RPC_S_OK)
  13361. {
  13362. // if this is the initial open and we are searching for the proxy, and
  13363. // the other channel opened,
  13364. // a failure here is not fatal. We'll just prevent further
  13365. // operations on the channel, and see what the other channel has
  13366. // to say. Note that during initial opening all the state is on the
  13367. // in channel - that's why we check InChannelState here, not OutChannelState
  13368. if ((IsReplacementChannel == FALSE)
  13369. && (InChannelState.State == http2svSearchProxy)
  13370. && (InOpenStatus == ERROR_IO_PENDING))
  13371. {
  13372. OutOpenStatus = RpcStatus;
  13373. SendOutChannel = FALSE;
  13374. ReceiveOutChannel = FALSE;
  13375. // we don't need to unlock the channel - the code
  13376. // below will do.
  13377. }
  13378. else
  13379. {
  13380. goto AbortAndExit;
  13381. }
  13382. }
  13383. }
  13384. // we're done with the opening itself. Unblock aborts
  13385. ASSERT(AbortsBlocked);
  13386. UnblockAborts();
  13387. AbortsBlocked = FALSE;
  13388. if (SendInChannel)
  13389. {
  13390. // should not happen during replacement
  13391. ASSERT(IsReplacementChannel == FALSE);
  13392. InChannelSendContext = AllocateAndInitializeD1_B1(HTTP2ProtocolVersion,
  13393. &EmbeddedConnectionCookie,
  13394. &InChannelCookies[0],
  13395. DefaultChannelLifetime,
  13396. DefaultClientKeepAliveInterval,
  13397. &Hint->AssociationGroupId
  13398. );
  13399. if (InChannelSendContext == NULL)
  13400. {
  13401. RpcStatus = RPC_S_OUT_OF_MEMORY;
  13402. goto AbortAndExit;
  13403. }
  13404. RpcStatus = NewInChannel->Send(InChannelSendContext);
  13405. if (RpcStatus != RPC_S_OK)
  13406. goto AbortAndExit;
  13407. // we don't own this buffer now
  13408. InChannelSendContext = NULL;
  13409. }
  13410. if (SendOutChannel)
  13411. {
  13412. // should not happen during replacement
  13413. ASSERT(IsReplacementChannel == FALSE);
  13414. OutChannelSendContext = AllocateAndInitializeD1_A1(HTTP2ProtocolVersion,
  13415. &EmbeddedConnectionCookie,
  13416. &OutChannelCookies[0],
  13417. HTTP2ClientReceiveWindow
  13418. );
  13419. if (OutChannelSendContext == NULL)
  13420. {
  13421. RpcStatus = RPC_S_OUT_OF_MEMORY;
  13422. goto AbortAndExit;
  13423. }
  13424. RpcStatus = NewOutChannel->Send(OutChannelSendContext);
  13425. if (RpcStatus != RPC_S_OK)
  13426. goto AbortAndExit;
  13427. // we don't own this buffer anymore
  13428. OutChannelSendContext = NULL;
  13429. }
  13430. // post receives on both channels
  13431. if (ReceiveOutChannel)
  13432. {
  13433. RpcStatus = NewOutChannel->Receive(http2ttRTS);
  13434. if (RpcStatus != RPC_S_OK)
  13435. {
  13436. goto AbortAndExit;
  13437. }
  13438. }
  13439. if (ReceiveInChannel)
  13440. {
  13441. RpcStatus = NewInChannel->Receive(http2ttRaw);
  13442. if (RpcStatus != RPC_S_OK)
  13443. goto AbortAndExit;
  13444. }
  13445. if (ResetInChannel || OpenInChannel || SendInChannel)
  13446. {
  13447. ASSERT(InChannelLocked);
  13448. InChannelPtr->UnlockChannelPointer();
  13449. InChannelLocked = FALSE;
  13450. // channel is unlocked. Can't touch it
  13451. NewInChannel = NULL;
  13452. }
  13453. if (ResetOutChannel || OpenOutChannel || SendOutChannel)
  13454. {
  13455. ASSERT(OutChannelLocked);
  13456. OutChannelPtr->UnlockChannelPointer();
  13457. OutChannelLocked = FALSE;
  13458. // channel is unlocked. Can't touch it
  13459. NewOutChannel = NULL;
  13460. }
  13461. if (IsDone)
  13462. {
  13463. RpcStatus = RPC_S_OK;
  13464. break;
  13465. }
  13466. // no authentication and single leg authentication are
  13467. // completed in one leg. Make sure we don't loop around
  13468. // with them for replacement case
  13469. if (ClientOpenInChannel && IsReplacementChannel)
  13470. {
  13471. ASSERT(InOpenType != cotNoAuth);
  13472. ASSERT(InOpenType != cotSLAuth);
  13473. ASSERT(InOpenType != cotMLAuth2);
  13474. }
  13475. if (ClientOpenOutChannel && IsReplacementChannel)
  13476. {
  13477. ASSERT(OutOpenType != cotNoAuth);
  13478. ASSERT(OutOpenType != cotSLAuth);
  13479. ASSERT(OutOpenType != cotMLAuth2);
  13480. }
  13481. WaitAgain:
  13482. // wait for something to happen
  13483. WaitResult = WaitForSingleObject(LocalClientOpenEvent, CallTimeout);
  13484. if (WaitResult == WAIT_TIMEOUT)
  13485. {
  13486. RpcStatus = RPC_S_CALL_CANCELLED;
  13487. goto AbortAndExit;
  13488. }
  13489. ASSERT(WaitResult == WAIT_OBJECT_0);
  13490. // there is race where we could have picked up a channel's event
  13491. // after we waited (e.g. two channels completed immediately after each
  13492. // other). In such case, there wouldn't be anything on any channel - wait
  13493. // again. This race exists only if we do initial connect.
  13494. if (IsReplacementChannel == FALSE)
  13495. {
  13496. if ((InOpenStatus == ERROR_IO_PENDING)
  13497. && (OutOpenStatus == ERROR_IO_PENDING))
  13498. {
  13499. goto WaitAgain;
  13500. }
  13501. }
  13502. OldInOpenType = InOpenType;
  13503. OldOutOpenType = OutOpenType;
  13504. // analyze what happened
  13505. // If we are in a non-terminal state, check what transitions we
  13506. // need to make to a terminal state
  13507. if (ClientOpenOutChannel
  13508. &&
  13509. (
  13510. (OutOpenType == cotSearchProxy)
  13511. ||
  13512. (OutOpenType == cotUnknownAuth)
  13513. )
  13514. )
  13515. {
  13516. OldOpenType = OutOpenType;
  13517. // We can be here in 3 cases:
  13518. // 1. We're searching for a proxy during initial open
  13519. // 2. We don't know the auth type during initial open
  13520. // 3. We recycle the out channel with unknown auth type
  13521. // The events of interest are:
  13522. // 1. If we are in case 2, and the channel is still pending,
  13523. // skip the channel.
  13524. // 2. If we're in the remainder of case 2 or we're in 3, or
  13525. // (we're in 1 and the in channel is not positive yet and we
  13526. // have given it enough time to come in, and we have a positive
  13527. // response on this channel), the result is final.
  13528. // 3. In case 1, if this channel has a negative response, fall through
  13529. // to both channel check
  13530. // 4. In case 1, if the other channel has come in, fall through
  13531. // capture the out open status to get a consistent view of it in
  13532. // the ifs below
  13533. LocalOutOpenStatus = OutOpenStatus;
  13534. if (OutOpenType == cotSearchProxy)
  13535. {
  13536. ASSERT(IsReplacementChannel == FALSE);
  13537. CurrentCase = 1;
  13538. }
  13539. else if (IsReplacementChannel == FALSE)
  13540. {
  13541. ASSERT(OutOpenType == cotUnknownAuth);
  13542. CurrentCase = 2;
  13543. }
  13544. else
  13545. {
  13546. ASSERT(IsReplacementChannel);
  13547. ASSERT(OutOpenType == cotUnknownAuth);
  13548. CurrentCase = 3;
  13549. }
  13550. if ((CurrentCase == 2)
  13551. && (LocalOutOpenStatus == ERROR_IO_PENDING))
  13552. {
  13553. NukeOutChannel = FALSE;
  13554. RebuildOutChannel = FALSE;
  13555. ResetOutChannel = FALSE;
  13556. OpenOutChannel = FALSE;
  13557. ReceiveOutChannel = FALSE;
  13558. SendOutChannel = FALSE;
  13559. }
  13560. else if
  13561. (
  13562. (CurrentCase == 2)
  13563. ||
  13564. (CurrentCase == 3)
  13565. ||
  13566. (
  13567. // positive response on case 1
  13568. (CurrentCase == 1)
  13569. &&
  13570. (!IsInChannelPositiveWithWait())
  13571. &&
  13572. (
  13573. (LocalOutOpenStatus == RPC_S_OK)
  13574. ||
  13575. (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  13576. )
  13577. )
  13578. )
  13579. {
  13580. // We'll be here in 3 cases
  13581. // 1. We don't know the auth type during initial open and we have
  13582. // a response on the channel
  13583. // 2. We recycle the out channel with unknown auth type
  13584. // 3. We search for a proxy and this channel will be chosen
  13585. // the status is final
  13586. if ((LocalOutOpenStatus != RPC_S_OK)
  13587. && (LocalOutOpenStatus != RPC_P_AUTH_NEEDED))
  13588. {
  13589. RpcStatus = LocalOutOpenStatus;
  13590. goto AbortAndExit;
  13591. }
  13592. // In all cases the auth scheme is final for the new channel and we
  13593. // need to continue authentication
  13594. // if we haven't chosen a scheme yet, choose it now
  13595. if (OutChosenAuthScheme == 0)
  13596. {
  13597. OutChosenAuthScheme = GetOutChannelChosenScheme(IsReplacementChannel);
  13598. }
  13599. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  13600. {
  13601. // milti legged authentication implies keep alives
  13602. IsKeepAlive = TRUE;
  13603. OutOpenType = cotMLAuth;
  13604. // we need only reset, open, send and receive
  13605. NukeOutChannel = FALSE;
  13606. RebuildOutChannel = FALSE;
  13607. ResetOutChannel = TRUE;
  13608. OpenOutChannel = TRUE;
  13609. SendOutChannel = FALSE;
  13610. ReceiveOutChannel = TRUE;
  13611. }
  13612. else
  13613. {
  13614. // SSL always supports keep alives
  13615. if (HttpCredentials && HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  13616. IsKeepAlive = TRUE;
  13617. else
  13618. {
  13619. IsKeepAlive = IsOutChannelKeepAlive(IsReplacementChannel);
  13620. }
  13621. if (OutChosenAuthScheme)
  13622. OutOpenType = cotSLAuth;
  13623. else
  13624. OutOpenType = cotNoAuth;
  13625. if (IsKeepAlive)
  13626. {
  13627. // we need nuke, rebuild, open, send, receive
  13628. NukeOutChannel = FALSE;
  13629. RebuildOutChannel = FALSE;
  13630. ResetOutChannel = TRUE;
  13631. }
  13632. else
  13633. {
  13634. // we need nuke, rebuild, open, send, receive
  13635. NukeOutChannel = TRUE;
  13636. RebuildOutChannel = TRUE;
  13637. ResetOutChannel = FALSE;
  13638. }
  13639. OpenOutChannel = TRUE;
  13640. if (IsReplacementChannel)
  13641. {
  13642. ReceiveOutChannel = FALSE;
  13643. // should be done on next iteration
  13644. IsDone = TRUE;
  13645. }
  13646. else
  13647. {
  13648. SendOutChannel = TRUE;
  13649. ReceiveOutChannel = TRUE;
  13650. }
  13651. }
  13652. OutOpenStatus = ERROR_IO_PENDING;
  13653. if (InOpenType == cotSearchProxy)
  13654. {
  13655. // we need to nuke, rebuild, open, send, possibly receive in channel
  13656. NukeInChannel = TRUE;
  13657. RebuildInChannel = TRUE;
  13658. ResetInChannel = FALSE;
  13659. OpenInChannel = TRUE;
  13660. SendInChannel = FALSE;
  13661. // if we have already chosen an auth scheme, presumably
  13662. // because of RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME, set it
  13663. if (InChosenAuthScheme)
  13664. {
  13665. ASSERT(IsReplacementChannel == FALSE);
  13666. ASSERT(HttpCredentials);
  13667. ASSERT(HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME);
  13668. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  13669. InOpenType = cotMLAuth;
  13670. else
  13671. {
  13672. InOpenType = cotSLAuth;
  13673. SendInChannel = TRUE;
  13674. }
  13675. }
  13676. else
  13677. InOpenType = cotUnknownAuth;
  13678. // multilegged schemes will still need to do some pinging.
  13679. // single legged schemes are done and only need to open
  13680. // the connection.
  13681. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  13682. ReceiveInChannel = TRUE;
  13683. else if (InOpenType == cotUnknownAuth)
  13684. {
  13685. ReceiveInChannel = TRUE;
  13686. }
  13687. else
  13688. {
  13689. ReceiveInChannel = FALSE;
  13690. }
  13691. StoredAccessType = rpcpatHTTPProxy;
  13692. Hint->AccessType = rpcpatHTTPProxy;
  13693. }
  13694. if (IsReplacementChannel == FALSE)
  13695. {
  13696. // change the connection and channel state
  13697. SetNewConnectionState = TRUE;
  13698. NewConnectionState = http2svA3W;
  13699. }
  13700. if ((OldOpenType == cotSearchProxy) || IsReplacementChannel)
  13701. continue;
  13702. else
  13703. {
  13704. // we were doing initial open with cotUnknownAuth
  13705. // fall through to the in channel handling code to see
  13706. // what is it up to
  13707. }
  13708. }
  13709. else
  13710. {
  13711. // events 3 and 4. We're searching for the proxy and
  13712. // either this channel came with a negative response or
  13713. // the other channel came in
  13714. ASSERT(CurrentCase == 1);
  13715. ASSERT(IsReplacementChannel == FALSE);
  13716. ASSERT(OutOpenType == cotSearchProxy);
  13717. ASSERT(
  13718. (
  13719. (LocalOutOpenStatus != RPC_S_OK)
  13720. &&
  13721. (LocalOutOpenStatus != RPC_P_AUTH_NEEDED)
  13722. )
  13723. ||
  13724. (
  13725. (InOpenStatus == RPC_S_OK)
  13726. ||
  13727. (InOpenStatus == RPC_P_AUTH_NEEDED)
  13728. )
  13729. );
  13730. // fall through to the in channel check
  13731. }
  13732. }
  13733. if (
  13734. ClientOpenInChannel
  13735. &&
  13736. (
  13737. (InOpenType == cotSearchProxy)
  13738. ||
  13739. (InOpenType == cotUnknownAuth)
  13740. )
  13741. )
  13742. {
  13743. OldOpenType = InOpenType;
  13744. // We can be here in 3 cases:
  13745. // 1. We do initial open and we search for proxy
  13746. // 2. We do initial open with unknown auth.
  13747. // 3. We do in channel recycling with unknown auth
  13748. // The events of interest are:
  13749. // 1. If the channel is still pending and we are in case 2,
  13750. // skip the channel.
  13751. // 2. If we're in case 3, or the remainder of 2, or (we're in 1 and
  13752. // the result is positive), the result is final.
  13753. // 3. If we're in case 1, and the result is negative, fall
  13754. // through below to both channels checks
  13755. if (InOpenType == cotSearchProxy)
  13756. {
  13757. ASSERT(IsReplacementChannel == FALSE);
  13758. CurrentCase = 1;
  13759. }
  13760. else if (IsReplacementChannel == FALSE)
  13761. {
  13762. ASSERT(InOpenType == cotUnknownAuth);
  13763. CurrentCase = 2;
  13764. }
  13765. else
  13766. {
  13767. ASSERT(IsReplacementChannel);
  13768. ASSERT(InOpenType == cotUnknownAuth);
  13769. CurrentCase = 3;
  13770. }
  13771. // capture the InOpenStatus to get a consistent view
  13772. LocalInOpenStatus = InOpenStatus;
  13773. if ((CurrentCase == 2) && (LocalInOpenStatus == ERROR_IO_PENDING))
  13774. {
  13775. NukeInChannel = FALSE;
  13776. RebuildInChannel = FALSE;
  13777. ResetInChannel = FALSE;
  13778. OpenInChannel = FALSE;
  13779. ReceiveInChannel = FALSE;
  13780. SendInChannel = FALSE;
  13781. // the wait must have been woken by the out channel. Loop around
  13782. continue;
  13783. }
  13784. else if
  13785. (
  13786. (CurrentCase == 2)
  13787. ||
  13788. (CurrentCase == 3)
  13789. ||
  13790. (
  13791. (CurrentCase == 1)
  13792. &&
  13793. (
  13794. (LocalInOpenStatus == RPC_S_OK)
  13795. ||
  13796. (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  13797. )
  13798. )
  13799. )
  13800. {
  13801. if ((LocalInOpenStatus != RPC_S_OK)
  13802. && (LocalInOpenStatus != RPC_P_AUTH_NEEDED))
  13803. {
  13804. RpcStatus = LocalInOpenStatus;
  13805. goto AbortAndExit;
  13806. }
  13807. // if we haven't chosen a scheme yet, choose it now
  13808. if (InChosenAuthScheme == 0)
  13809. {
  13810. InChosenAuthScheme = GetInChannelChosenScheme(IsReplacementChannel);
  13811. }
  13812. if (InChosenAuthScheme & MultiLeggedSchemeMap)
  13813. {
  13814. // milti legged authentication implies keep alives
  13815. IsKeepAlive = TRUE;
  13816. InOpenType = cotMLAuth;
  13817. // we need only reset, open, send and receive
  13818. NukeInChannel = FALSE;
  13819. RebuildInChannel = FALSE;
  13820. ResetInChannel = TRUE;
  13821. OpenInChannel = TRUE;
  13822. SendInChannel = FALSE;
  13823. ReceiveInChannel = TRUE;
  13824. }
  13825. else
  13826. {
  13827. // SSL always supports keep alives
  13828. if (HttpCredentials && HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)
  13829. IsKeepAlive = TRUE;
  13830. else
  13831. {
  13832. IsKeepAlive = IsInChannelKeepAlive(IsReplacementChannel);
  13833. }
  13834. if (InChosenAuthScheme)
  13835. InOpenType = cotSLAuth;
  13836. else
  13837. InOpenType = cotNoAuth;
  13838. if (IsKeepAlive)
  13839. {
  13840. // we need nuke, rebuild, open, send, receive
  13841. NukeInChannel = FALSE;
  13842. RebuildInChannel = FALSE;
  13843. ResetInChannel = TRUE;
  13844. }
  13845. else
  13846. {
  13847. // we need nuke, rebuild, open, send, receive
  13848. NukeInChannel = TRUE;
  13849. RebuildInChannel = TRUE;
  13850. ResetInChannel = FALSE;
  13851. }
  13852. OpenInChannel = TRUE;
  13853. if (IsReplacementChannel)
  13854. IsDone = TRUE;
  13855. else
  13856. SendInChannel = TRUE;
  13857. if (UseWinHttp || (IsReplacementChannel == FALSE))
  13858. ReceiveInChannel = FALSE;
  13859. else
  13860. ReceiveInChannel = TRUE;
  13861. }
  13862. InOpenStatus = ERROR_IO_PENDING;
  13863. if (OutOpenType == cotSearchProxy)
  13864. {
  13865. // we need to nuke, rebuild, open, send, possibly receive in channel
  13866. NukeOutChannel = TRUE;
  13867. RebuildOutChannel = TRUE;
  13868. ResetOutChannel = FALSE;
  13869. OpenOutChannel = TRUE;
  13870. SendOutChannel = FALSE;
  13871. ReceiveOutChannel = TRUE;
  13872. // if we have already chosen an auth scheme, presumably
  13873. // because of RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME, set it
  13874. if (OutChosenAuthScheme)
  13875. {
  13876. ASSERT(IsReplacementChannel == FALSE);
  13877. ASSERT(HttpCredentials);
  13878. ASSERT(HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME);
  13879. if (OutChosenAuthScheme & MultiLeggedSchemeMap)
  13880. OutOpenType = cotMLAuth;
  13881. else
  13882. {
  13883. OutOpenType = cotSLAuth;
  13884. SendOutChannel = TRUE;
  13885. }
  13886. }
  13887. else
  13888. OutOpenType = cotUnknownAuth;
  13889. StoredAccessType = rpcpatDirect;
  13890. Hint->AccessType = rpcpatDirect;
  13891. }
  13892. if (IsReplacementChannel == FALSE)
  13893. {
  13894. // change the connection and channel state
  13895. SetNewConnectionState = TRUE;
  13896. NewConnectionState = http2svA3W;
  13897. }
  13898. if ((OldOpenType == cotSearchProxy) || IsReplacementChannel)
  13899. continue;
  13900. else
  13901. {
  13902. // fall through to code that handles both channels
  13903. }
  13904. }
  13905. else
  13906. {
  13907. ASSERT(CurrentCase == 1);
  13908. ASSERT((LocalInOpenStatus != RPC_S_OK)
  13909. && (LocalInOpenStatus != RPC_P_AUTH_NEEDED) );
  13910. // fall through below
  13911. }
  13912. }
  13913. // did we get to an opened state? This should be checked only
  13914. // when we open both (initial open).
  13915. if ((IsReplacementChannel == FALSE)
  13916. && (InChannelState.State == http2svOpened))
  13917. {
  13918. RpcStatus = RPC_S_OK;
  13919. ASSERT(InChannelState.State == http2svOpened);
  13920. ASSERT(OutChannelState.State == http2svOpened);
  13921. RpcStatus = HTTP_CopyResolverHint(&ConnectionHint,
  13922. Hint,
  13923. FALSE // SourceWillBeAbandoned
  13924. );
  13925. if (RpcStatus != RPC_S_OK)
  13926. goto AbortAndExit;
  13927. break;
  13928. }
  13929. // if we are in a non-transitional state and we're doing an
  13930. // initial open, this means one of the channels didn't come in.
  13931. // Loop around
  13932. if ((IsReplacementChannel == FALSE)
  13933. && (
  13934. (InOpenType == cotUnknownAuth)
  13935. ||
  13936. (OutOpenType == cotUnknownAuth)
  13937. )
  13938. )
  13939. {
  13940. ASSERT((LocalInOpenStatus == ERROR_IO_PENDING)
  13941. || (LocalOutOpenStatus == ERROR_IO_PENDING));
  13942. continue;
  13943. }
  13944. // we're probably authenticating the individual channels
  13945. // see which channel is actionable and what to do with it
  13946. if (ClientOpenInChannel && (OldInOpenType == cotMLAuth))
  13947. {
  13948. // capture the InOpenStatus in a local variable for consistent
  13949. // view
  13950. LocalInOpenStatus = InOpenStatus;
  13951. if (LocalInOpenStatus != ERROR_IO_PENDING)
  13952. {
  13953. // something happened on the in channel. Process it
  13954. if (LocalInOpenStatus == RPC_S_OK)
  13955. {
  13956. // we have successfully completed
  13957. // authentication. Open the connection on the RTS
  13958. // level
  13959. InOpenStatus = ERROR_IO_PENDING;
  13960. // we need to reset, open, send, receive out channel
  13961. NukeInChannel = FALSE;
  13962. RebuildInChannel = FALSE;
  13963. ResetInChannel = TRUE;
  13964. OpenInChannel = TRUE;
  13965. ReceiveInChannel = FALSE;
  13966. if (IsReplacementChannel)
  13967. {
  13968. SendInChannel = FALSE;
  13969. IsDone = TRUE;
  13970. }
  13971. else
  13972. SendInChannel = TRUE;
  13973. InOpenType = cotMLAuth2;
  13974. }
  13975. else
  13976. {
  13977. // if after all the auth we still get a challenge, this means
  13978. // we couldn't auth and this is access denied.
  13979. if (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  13980. RpcStatus = RPC_S_ACCESS_DENIED;
  13981. else
  13982. RpcStatus = LocalInOpenStatus;
  13983. goto AbortAndExit;
  13984. }
  13985. }
  13986. else
  13987. {
  13988. // fall through. Below we will detect the state
  13989. // hasn't changed and we won't do any operations
  13990. // on this channel
  13991. }
  13992. }
  13993. if (ClientOpenOutChannel && (OldOutOpenType == cotMLAuth))
  13994. {
  13995. // capture the OutOpenStatus in a local variable for consistent
  13996. // view
  13997. LocalOutOpenStatus = OutOpenStatus;
  13998. if (LocalOutOpenStatus != ERROR_IO_PENDING)
  13999. {
  14000. // something happened on the in channel. Process it
  14001. if (LocalOutOpenStatus == RPC_S_OK)
  14002. {
  14003. // we have successfully completed multi-legged
  14004. // authentication. Open the connection on the RTS
  14005. // level
  14006. OutOpenStatus = ERROR_IO_PENDING;
  14007. // we need to reset, open, send, receive out channel
  14008. NukeOutChannel = FALSE;
  14009. RebuildOutChannel = FALSE;
  14010. ResetOutChannel = TRUE;
  14011. OpenOutChannel = TRUE;
  14012. if (IsReplacementChannel)
  14013. {
  14014. ReceiveOutChannel = FALSE;
  14015. SendOutChannel = FALSE;
  14016. IsDone = TRUE;
  14017. }
  14018. else
  14019. {
  14020. ReceiveOutChannel = TRUE;
  14021. SendOutChannel = TRUE;
  14022. }
  14023. OutOpenType = cotMLAuth2;
  14024. }
  14025. else
  14026. {
  14027. // if after all the auth we still get a challenge, this means
  14028. // we couldn't auth and this is access denied.
  14029. if (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  14030. RpcStatus = RPC_S_ACCESS_DENIED;
  14031. else
  14032. RpcStatus = LocalOutOpenStatus;
  14033. goto AbortAndExit;
  14034. }
  14035. }
  14036. else
  14037. {
  14038. // fall through. Below we will detect the state
  14039. // hasn't changed and we won't do any operations
  14040. // on this channel
  14041. }
  14042. }
  14043. if ((IsReplacementChannel == FALSE) && (InOpenType == cotSearchProxy))
  14044. {
  14045. // none of the channels came in positive so far. If at least one
  14046. // is still pending, wait for it
  14047. if ((LocalInOpenStatus == ERROR_IO_PENDING)
  14048. || (LocalOutOpenStatus == ERROR_IO_PENDING))
  14049. {
  14050. #if DBG_ERROR
  14051. DbgPrint("Waiting again ....\n");
  14052. #endif
  14053. goto WaitAgain;
  14054. }
  14055. // both channels came in negative. The server is not
  14056. // available
  14057. if ((LocalInOpenStatus == RPC_S_ACCESS_DENIED)
  14058. || (LocalOutOpenStatus == RPC_S_ACCESS_DENIED))
  14059. RpcStatus = RPC_S_ACCESS_DENIED;
  14060. else
  14061. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  14062. goto AbortAndExit;
  14063. }
  14064. // if we came in with a terminal state and the server responded
  14065. // with an error, bail out
  14066. // first, capture the InOpenStatus in a local variable for consistent
  14067. // view
  14068. LocalInOpenStatus = InOpenStatus;
  14069. if (ClientOpenInChannel
  14070. &&
  14071. (
  14072. (OldInOpenType == cotSLAuth)
  14073. ||
  14074. (OldInOpenType == cotNoAuth)
  14075. ||
  14076. (OldInOpenType == cotMLAuth2)
  14077. )
  14078. &&
  14079. (LocalInOpenStatus != RPC_S_OK)
  14080. &&
  14081. (LocalInOpenStatus != ERROR_IO_PENDING)
  14082. )
  14083. {
  14084. if (LocalInOpenStatus == RPC_P_AUTH_NEEDED)
  14085. RpcStatus = RPC_S_ACCESS_DENIED;
  14086. else
  14087. RpcStatus = LocalInOpenStatus;
  14088. goto AbortAndExit;
  14089. }
  14090. // capture the OutOpenStatus in a local variable for consistent
  14091. // view
  14092. LocalOutOpenStatus = OutOpenStatus;
  14093. if (ClientOpenOutChannel
  14094. &&
  14095. (
  14096. (OldOutOpenType == cotSLAuth)
  14097. ||
  14098. (OldOutOpenType == cotNoAuth)
  14099. ||
  14100. (OldOutOpenType == cotMLAuth2)
  14101. )
  14102. &&
  14103. (LocalOutOpenStatus != RPC_S_OK)
  14104. &&
  14105. (LocalOutOpenStatus != ERROR_IO_PENDING)
  14106. )
  14107. {
  14108. if (LocalOutOpenStatus == RPC_P_AUTH_NEEDED)
  14109. RpcStatus = RPC_S_ACCESS_DENIED;
  14110. else
  14111. RpcStatus = LocalOutOpenStatus;
  14112. goto AbortAndExit;
  14113. }
  14114. // if state hasn't changed, don't do anything on this channel
  14115. if (OldInOpenType == InOpenType)
  14116. {
  14117. NukeInChannel = FALSE;
  14118. RebuildInChannel = FALSE;
  14119. ResetInChannel = FALSE;
  14120. OpenInChannel = FALSE;
  14121. ReceiveInChannel = FALSE;
  14122. SendInChannel = FALSE;
  14123. }
  14124. if (OldOutOpenType == OutOpenType)
  14125. {
  14126. NukeOutChannel = FALSE;
  14127. RebuildOutChannel = FALSE;
  14128. ResetOutChannel = FALSE;
  14129. OpenOutChannel = FALSE;
  14130. ReceiveOutChannel = FALSE;
  14131. SendOutChannel = FALSE;
  14132. }
  14133. // loop around for further processing
  14134. }
  14135. if (AbortsBlocked)
  14136. UnblockAborts();
  14137. ASSERT(RpcStatus == RPC_S_OK);
  14138. if (IsReplacementChannel == FALSE)
  14139. {
  14140. ASSERT(InChannelState.State == http2svOpened);
  14141. }
  14142. ASSERT(LocalClientOpenEvent);
  14143. InChannelState.Mutex.Request();
  14144. ClientOpenInEvent = NULL;
  14145. ClientOpenOutEvent = NULL;
  14146. InChannelState.Mutex.Clear();
  14147. CloseHandle(LocalClientOpenEvent);
  14148. return RpcStatus;
  14149. AbortAndExit:
  14150. if (InChannelLocked)
  14151. {
  14152. InChannelPtr->UnlockChannelPointer();
  14153. }
  14154. if (OutChannelLocked)
  14155. {
  14156. OutChannelPtr->UnlockChannelPointer();
  14157. }
  14158. if (InChannelSendContext)
  14159. {
  14160. FreeRTSPacket(InChannelSendContext);
  14161. }
  14162. if (OutChannelSendContext)
  14163. {
  14164. FreeRTSPacket(OutChannelSendContext);
  14165. }
  14166. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  14167. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  14168. || (RpcStatus == RPC_P_SEND_FAILED))
  14169. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  14170. else if ((RpcStatus == RPC_P_RECEIVE_FAILED) && IsReplacementChannel)
  14171. {
  14172. // RPC_P_RECEIVE_FAILED is also mapped to server unavailable, but only
  14173. // during channel recycling. The reason is that the old crappy RPC Proxy
  14174. // will just close the connection if we directly access the RPC Proxy,
  14175. // so all that we will get will be RPC_P_RECEIVE_FAILED. Not mapping it
  14176. // during initial conneciton establishment allows upper layers to try the old
  14177. // HTTP thus preserving interop
  14178. RpcStatus = RPC_S_SERVER_UNAVAILABLE;
  14179. }
  14180. else if (RpcStatus == ERROR_NOT_ENOUGH_QUOTA
  14181. || RpcStatus == ERROR_MAX_THRDS_REACHED)
  14182. {
  14183. RpcStatus = RPC_S_OUT_OF_MEMORY;
  14184. }
  14185. ASSERT(LocalClientOpenEvent);
  14186. InChannelState.Mutex.Request();
  14187. ClientOpenInEvent = NULL;
  14188. ClientOpenOutEvent = NULL;
  14189. InChannelState.Mutex.Clear();
  14190. CloseHandle(LocalClientOpenEvent);
  14191. VALIDATE (RpcStatus)
  14192. {
  14193. RPC_S_PROTSEQ_NOT_SUPPORTED,
  14194. RPC_S_SERVER_UNAVAILABLE,
  14195. RPC_S_OUT_OF_MEMORY,
  14196. RPC_S_OUT_OF_RESOURCES,
  14197. RPC_S_SERVER_TOO_BUSY,
  14198. RPC_S_INVALID_NETWORK_OPTIONS,
  14199. RPC_S_INVALID_ENDPOINT_FORMAT,
  14200. RPC_S_INVALID_NET_ADDR,
  14201. RPC_S_ACCESS_DENIED,
  14202. RPC_S_INTERNAL_ERROR,
  14203. RPC_S_SERVER_OUT_OF_MEMORY,
  14204. RPC_S_CALL_CANCELLED,
  14205. RPC_S_PROTOCOL_ERROR,
  14206. RPC_P_RECEIVE_FAILED
  14207. } END_VALIDATE;
  14208. if (AbortsBlocked)
  14209. UnblockAborts();
  14210. // If we are not from upcall, abort. Else, caller will
  14211. // abort
  14212. if (IsFromUpcall == FALSE)
  14213. Abort();
  14214. return RpcStatus;
  14215. }
  14216. RPC_STATUS HTTP2ClientVirtualConnection::AllocateAndInitializeInChannel (
  14217. IN HTTPResolverHint *Hint,
  14218. IN BOOL HintWasInitialized,
  14219. IN ULONG CallTimeout,
  14220. IN BOOL UseWinHttp,
  14221. OUT HTTP2ClientInChannel **ReturnInChannel
  14222. )
  14223. /*++
  14224. Routine Description:
  14225. Allocate and initialize the in channel stack
  14226. Arguments:
  14227. Hint - the resolver hint
  14228. HintWasInitialized - true if the hint was initialized on input
  14229. CallTimeout - the timeout for the operation
  14230. ReturnInChannel - on success the pointer to the allocated in channel.
  14231. Undefined on failure.
  14232. UseWinHttp - non-zero if WinHttp should be used for the bottom channel.
  14233. Return Value:
  14234. RPC_S_OK or other RPC_S_* errors for error
  14235. --*/
  14236. {
  14237. ULONG MemorySize;
  14238. BYTE *MemoryBlock, *CurrentBlock;
  14239. HTTP2ClientInChannel *InChannel;
  14240. HTTP2PlugChannel *PlugChannel;
  14241. HTTP2FlowControlSender *FlowControlSender;
  14242. HTTP2PingOriginator *PingOriginator;
  14243. HTTP2ChannelDataOriginator *ChannelDataOriginator;
  14244. HTTP2SocketTransportChannel *RawChannel;
  14245. WS_HTTP2_CONNECTION *RawConnection;
  14246. HTTP2WinHttpTransportChannel *WinHttpConnection;
  14247. BOOL PlugChannelNeedsCleanup;
  14248. BOOL FlowControlSenderNeedsCleanup;
  14249. BOOL PingOriginatorNeedsCleanup;
  14250. BOOL ChannelDataOriginatorNeedsCleanup;
  14251. BOOL RawChannelNeedsCleanup;
  14252. BOOL RawConnectionNeedsCleanup;
  14253. BOOL WinHttpConnectionNeedsCleanup;
  14254. RPC_STATUS RpcStatus;
  14255. // alocate the in channel
  14256. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientInChannel)
  14257. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel)
  14258. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  14259. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator)
  14260. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator)
  14261. ;
  14262. if (UseWinHttp)
  14263. MemorySize += sizeof(HTTP2WinHttpTransportChannel);
  14264. else
  14265. {
  14266. MemorySize += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  14267. + sizeof(WS_HTTP2_CONNECTION);
  14268. }
  14269. CurrentBlock = MemoryBlock = (BYTE *) new char [MemorySize];
  14270. if (CurrentBlock == NULL)
  14271. return RPC_S_OUT_OF_MEMORY;
  14272. InChannel = (HTTP2ClientInChannel *) MemoryBlock;
  14273. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientInChannel);
  14274. PlugChannel = (HTTP2PlugChannel *) CurrentBlock;
  14275. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel);
  14276. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  14277. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  14278. PingOriginator = (HTTP2PingOriginator *)CurrentBlock;
  14279. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator);
  14280. ChannelDataOriginator = (HTTP2ChannelDataOriginator *)CurrentBlock;
  14281. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator);
  14282. if (UseWinHttp)
  14283. {
  14284. WinHttpConnection = (HTTP2WinHttpTransportChannel *)CurrentBlock;
  14285. }
  14286. else
  14287. {
  14288. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  14289. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  14290. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  14291. RawConnection->HeaderRead = FALSE;
  14292. RawConnection->ReadHeaderFn = HTTP2ClientReadChannelHeader;
  14293. }
  14294. // all memory blocks are allocated. Go and initialize them. Use explicit
  14295. // placement
  14296. PlugChannelNeedsCleanup = FALSE;
  14297. FlowControlSenderNeedsCleanup = FALSE;
  14298. PingOriginatorNeedsCleanup = FALSE;
  14299. ChannelDataOriginatorNeedsCleanup = FALSE;
  14300. RawChannelNeedsCleanup = FALSE;
  14301. RawConnectionNeedsCleanup = FALSE;
  14302. WinHttpConnectionNeedsCleanup = FALSE;
  14303. if (UseWinHttp)
  14304. {
  14305. RpcStatus = RPC_S_OK;
  14306. WinHttpConnection = new (WinHttpConnection) HTTP2WinHttpTransportChannel (&RpcStatus);
  14307. if (RpcStatus != RPC_S_OK)
  14308. {
  14309. WinHttpConnection->HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  14310. goto AbortAndExit;
  14311. }
  14312. WinHttpConnectionNeedsCleanup = TRUE;
  14313. }
  14314. else
  14315. {
  14316. RpcStatus = InitializeRawConnection (RawConnection,
  14317. Hint,
  14318. HintWasInitialized,
  14319. CallTimeout
  14320. );
  14321. if (RpcStatus != RPC_S_OK)
  14322. goto AbortAndExit;
  14323. RawConnection->RuntimeConnectionPtr = this;
  14324. RawConnectionNeedsCleanup = TRUE;
  14325. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  14326. if (RpcStatus != RPC_S_OK)
  14327. {
  14328. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  14329. goto AbortAndExit;
  14330. }
  14331. RawConnection->Channel = RawChannel;
  14332. RawChannelNeedsCleanup = TRUE;
  14333. }
  14334. ChannelDataOriginator = new (ChannelDataOriginator) HTTP2ChannelDataOriginator (DefaultChannelLifetime,
  14335. FALSE, // IsServer
  14336. &RpcStatus);
  14337. if (RpcStatus != RPC_S_OK)
  14338. {
  14339. ChannelDataOriginator->HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  14340. goto AbortAndExit;
  14341. }
  14342. if (UseWinHttp)
  14343. {
  14344. WinHttpConnection->SetUpperChannel(ChannelDataOriginator);
  14345. ChannelDataOriginator->SetLowerChannel(WinHttpConnection);
  14346. }
  14347. else
  14348. {
  14349. RawChannel->SetUpperChannel(ChannelDataOriginator);
  14350. ChannelDataOriginator->SetLowerChannel(RawChannel);
  14351. }
  14352. ChannelDataOriginatorNeedsCleanup = TRUE;
  14353. PingOriginator = new (PingOriginator) HTTP2PingOriginator (
  14354. FALSE // NotifyTopChannelForPings
  14355. );
  14356. ChannelDataOriginator->SetUpperChannel(PingOriginator);
  14357. PingOriginator->SetLowerChannel(ChannelDataOriginator);
  14358. PingOriginatorNeedsCleanup = TRUE;
  14359. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  14360. TRUE, // SendToRuntime
  14361. &RpcStatus
  14362. );
  14363. if (RpcStatus != RPC_S_OK)
  14364. {
  14365. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  14366. goto AbortAndExit;
  14367. }
  14368. PingOriginator->SetUpperChannel(FlowControlSender);
  14369. FlowControlSender->SetLowerChannel(PingOriginator);
  14370. FlowControlSenderNeedsCleanup = TRUE;
  14371. PlugChannel = new (PlugChannel) HTTP2PlugChannel (&RpcStatus);
  14372. if (RpcStatus != RPC_S_OK)
  14373. {
  14374. PlugChannel->HTTP2PlugChannel::~HTTP2PlugChannel();
  14375. goto AbortAndExit;
  14376. }
  14377. FlowControlSender->SetUpperChannel(PlugChannel);
  14378. PlugChannel->SetLowerChannel(FlowControlSender);
  14379. PlugChannelNeedsCleanup = TRUE;
  14380. InChannel = new (InChannel) HTTP2ClientInChannel (this, &RpcStatus);
  14381. if (RpcStatus != RPC_S_OK)
  14382. {
  14383. InChannel->HTTP2ClientInChannel::~HTTP2ClientInChannel();
  14384. goto AbortAndExit;
  14385. }
  14386. if (UseWinHttp)
  14387. WinHttpConnection->SetTopChannel(InChannel);
  14388. else
  14389. RawChannel->SetTopChannel(InChannel);
  14390. ChannelDataOriginator->SetTopChannel(InChannel);
  14391. PingOriginator->SetTopChannel(InChannel);
  14392. FlowControlSender->SetTopChannel(InChannel);
  14393. PlugChannel->SetTopChannel(InChannel);
  14394. PlugChannel->SetUpperChannel(InChannel);
  14395. InChannel->SetLowerChannel(PlugChannel);
  14396. ASSERT(RpcStatus == RPC_S_OK);
  14397. *ReturnInChannel = InChannel;
  14398. goto CleanupAndExit;
  14399. AbortAndExit:
  14400. if (PlugChannelNeedsCleanup)
  14401. {
  14402. PlugChannel->Abort(RpcStatus);
  14403. PlugChannel->FreeObject();
  14404. }
  14405. else if (FlowControlSenderNeedsCleanup)
  14406. {
  14407. FlowControlSender->Abort(RpcStatus);
  14408. FlowControlSender->FreeObject();
  14409. }
  14410. else if (PingOriginatorNeedsCleanup)
  14411. {
  14412. PingOriginator->Abort(RpcStatus);
  14413. PingOriginator->FreeObject();
  14414. }
  14415. else if (ChannelDataOriginatorNeedsCleanup)
  14416. {
  14417. ChannelDataOriginator->Abort(RpcStatus);
  14418. ChannelDataOriginator->FreeObject();
  14419. }
  14420. else if (UseWinHttp)
  14421. {
  14422. if (WinHttpConnectionNeedsCleanup)
  14423. {
  14424. WinHttpConnection->Abort(RpcStatus);
  14425. WinHttpConnection->FreeObject();
  14426. }
  14427. }
  14428. else if (RawChannelNeedsCleanup)
  14429. {
  14430. RawChannel->Abort(RpcStatus);
  14431. RawChannel->FreeObject();
  14432. }
  14433. else if (RawConnectionNeedsCleanup)
  14434. {
  14435. RawConnection->RealAbort();
  14436. }
  14437. if (MemoryBlock)
  14438. delete [] MemoryBlock;
  14439. CleanupAndExit:
  14440. return RpcStatus;
  14441. }
  14442. RPC_STATUS
  14443. RPC_ENTRY
  14444. HTTP2ReadHttpLegacyResponse (
  14445. IN WS_HTTP2_CONNECTION *Connection,
  14446. IN ULONG BytesRead,
  14447. OUT ULONG *NewBytesRead
  14448. )
  14449. /*++
  14450. Routine Description:
  14451. Read a channel HTTP header (usually some string). In success
  14452. case, there is real data in Connection->pReadBuffer. The
  14453. number of bytes there is in NewBytesRead
  14454. Arguments:
  14455. Connection - the connection on which the header arrived.
  14456. BytesRead - the bytes received from the net
  14457. NewBytesRead - the bytes read from the channel (success only)
  14458. Return Value:
  14459. RPC_S_OK or other RPC_S_* errors for error
  14460. RPC_P_PARTIAL_RECEIVE will cause another loop.
  14461. Any other error will cause processing of NewBuffer
  14462. --*/
  14463. {
  14464. RPC_STATUS RpcStatus;
  14465. BYTE *NewBuffer;
  14466. BytesRead += Connection->iLastRead;
  14467. // check whether what we have is a legacy response
  14468. // legacy response is ncacn_http/1.0
  14469. if (*(ULONG *)Connection->pReadBuffer == (ULONG)'cacn')
  14470. {
  14471. // Let's process it now.
  14472. // see if we have sufficient length
  14473. if (BytesRead < HTTP_SERVER_ID_STR_LEN)
  14474. {
  14475. Connection->iLastRead = BytesRead;
  14476. return RPC_P_PARTIAL_RECEIVE;
  14477. }
  14478. else if (BytesRead == HTTP_SERVER_ID_STR_LEN)
  14479. {
  14480. // reset the pointer. By doing so we forget all we have
  14481. // read so far
  14482. Connection->iLastRead = 0;
  14483. Connection->HeaderRead = TRUE;
  14484. return RPC_P_PARTIAL_RECEIVE;
  14485. }
  14486. else
  14487. {
  14488. // we have what we expect, and something more (coalesced read)
  14489. // Process it. First make sure it is what we expect
  14490. if (RpcpMemoryCompare(Connection->pReadBuffer, HTTP_SERVER_ID_STR, HTTP_SERVER_ID_STR_LEN) != 0)
  14491. {
  14492. return RPC_S_PROTOCOL_ERROR;
  14493. }
  14494. NewBuffer = TransConnectionAllocatePacket(Connection,
  14495. max(Connection->iPostSize, BytesRead - HTTP_SERVER_ID_STR_LEN));
  14496. if (0 == NewBuffer)
  14497. return RPC_S_OUT_OF_MEMORY;
  14498. RpcpMemoryCopy(NewBuffer,
  14499. ((BYTE *)Connection->pReadBuffer) + HTTP_SERVER_ID_STR_LEN,
  14500. BytesRead - HTTP_SERVER_ID_STR_LEN);
  14501. *NewBytesRead = BytesRead - HTTP_SERVER_ID_STR_LEN;
  14502. RpcFreeBuffer(Connection->pReadBuffer);
  14503. Connection->pReadBuffer = NewBuffer;
  14504. Connection->iLastRead = 0;
  14505. Connection->HeaderRead = TRUE;
  14506. return RPC_S_OK;
  14507. }
  14508. }
  14509. else
  14510. {
  14511. *NewBytesRead = BytesRead;
  14512. Connection->iLastRead = 0;
  14513. Connection->HeaderRead = TRUE;
  14514. return RPC_S_OK;
  14515. }
  14516. }
  14517. RPC_STATUS HTTP2ClientVirtualConnection::AllocateAndInitializeOutChannel (
  14518. IN HTTPResolverHint *Hint,
  14519. IN BOOL HintWasInitialized,
  14520. IN ULONG CallTimeout,
  14521. IN BOOL UseWinHttp,
  14522. OUT HTTP2ClientOutChannel **ReturnOutChannel
  14523. )
  14524. /*++
  14525. Routine Description:
  14526. Allocate and initialize the out channel stack
  14527. Arguments:
  14528. Hint - the resolver hint
  14529. HintWasInitialized - true if the hint was initialized on input
  14530. CallTimeout - the timeout for the operation
  14531. ReturnInChannel - on success the pointer to the allocated in channel.
  14532. Undefined on failure.
  14533. UseWinHttp - non-zero if WinHttp should be used for the bottom channel.
  14534. Return Value:
  14535. RPC_S_OK or other RPC_S_* errors for error
  14536. --*/
  14537. {
  14538. ULONG MemorySize;
  14539. BYTE *MemoryBlock, *CurrentBlock;
  14540. HTTP2ClientOutChannel *OutChannel;
  14541. HTTP2EndpointReceiver *EndpointReceiver;
  14542. HTTP2PingReceiver *PingReceiver;
  14543. HTTP2SocketTransportChannel *RawChannel;
  14544. WS_HTTP2_CONNECTION *RawConnection;
  14545. HTTP2WinHttpTransportChannel *WinHttpConnection;
  14546. BOOL EndpointReceiverNeedsCleanup;
  14547. BOOL PingReceiverNeedsCleanup;
  14548. BOOL RawChannelNeedsCleanup;
  14549. BOOL RawConnectionNeedsCleanup;
  14550. BOOL WinHttpConnectionNeedsCleanup;
  14551. RPC_STATUS RpcStatus;
  14552. // alocate the out channel
  14553. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientOutChannel)
  14554. + SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver)
  14555. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  14556. ;
  14557. if (UseWinHttp)
  14558. MemorySize += sizeof(HTTP2WinHttpTransportChannel);
  14559. else
  14560. {
  14561. MemorySize += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  14562. + sizeof(WS_HTTP2_CONNECTION);
  14563. }
  14564. CurrentBlock = MemoryBlock = (BYTE *) new char [MemorySize];
  14565. if (CurrentBlock == NULL)
  14566. return RPC_S_OUT_OF_MEMORY;
  14567. OutChannel = (HTTP2ClientOutChannel *) MemoryBlock;
  14568. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ClientOutChannel);
  14569. EndpointReceiver = (HTTP2EndpointReceiver *)CurrentBlock;
  14570. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver);
  14571. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  14572. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  14573. if (UseWinHttp)
  14574. {
  14575. WinHttpConnection = (HTTP2WinHttpTransportChannel *)CurrentBlock;
  14576. }
  14577. else
  14578. {
  14579. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  14580. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  14581. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  14582. RawConnection->HeaderRead = FALSE;
  14583. RawConnection->ReadHeaderFn = HTTP2ClientReadChannelHeader;
  14584. }
  14585. // all memory blocks are allocated. Go and initialize them. Use explicit
  14586. // placement
  14587. EndpointReceiverNeedsCleanup = FALSE;
  14588. PingReceiverNeedsCleanup = FALSE;
  14589. RawChannelNeedsCleanup = FALSE;
  14590. RawConnectionNeedsCleanup = FALSE;
  14591. WinHttpConnectionNeedsCleanup = FALSE;
  14592. if (UseWinHttp)
  14593. {
  14594. RpcStatus = RPC_S_OK;
  14595. WinHttpConnection = new (WinHttpConnection) HTTP2WinHttpTransportChannel (&RpcStatus);
  14596. if (RpcStatus != RPC_S_OK)
  14597. {
  14598. WinHttpConnection->HTTP2WinHttpTransportChannel::~HTTP2WinHttpTransportChannel();
  14599. goto AbortAndExit;
  14600. }
  14601. WinHttpConnectionNeedsCleanup = TRUE;
  14602. }
  14603. else
  14604. {
  14605. RpcStatus = InitializeRawConnection (RawConnection,
  14606. Hint,
  14607. HintWasInitialized,
  14608. CallTimeout
  14609. );
  14610. if (RpcStatus != RPC_S_OK)
  14611. goto AbortAndExit;
  14612. RawConnection->RuntimeConnectionPtr = this;
  14613. RawConnectionNeedsCleanup = TRUE;
  14614. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  14615. if (RpcStatus != RPC_S_OK)
  14616. {
  14617. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  14618. goto AbortAndExit;
  14619. }
  14620. RawConnection->Channel = RawChannel;
  14621. RawChannelNeedsCleanup = TRUE;
  14622. }
  14623. PingReceiver = new (PingReceiver) HTTP2PingReceiver(TRUE);
  14624. if (UseWinHttp)
  14625. {
  14626. WinHttpConnection->SetUpperChannel(PingReceiver);
  14627. PingReceiver->SetLowerChannel(WinHttpConnection);
  14628. }
  14629. else
  14630. {
  14631. RawChannel->SetUpperChannel(PingReceiver);
  14632. PingReceiver->SetLowerChannel(RawChannel);
  14633. }
  14634. PingReceiverNeedsCleanup = TRUE;
  14635. EndpointReceiver = new (EndpointReceiver) HTTP2EndpointReceiver(HTTP2ClientReceiveWindow,
  14636. FALSE, // IsServer
  14637. &RpcStatus);
  14638. if (RpcStatus != RPC_S_OK)
  14639. {
  14640. EndpointReceiver->HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  14641. goto AbortAndExit;
  14642. }
  14643. PingReceiver->SetUpperChannel(EndpointReceiver);
  14644. EndpointReceiver->SetLowerChannel(PingReceiver);
  14645. EndpointReceiverNeedsCleanup = TRUE;
  14646. OutChannel = new (OutChannel) HTTP2ClientOutChannel (this, &RpcStatus);
  14647. if (RpcStatus != RPC_S_OK)
  14648. {
  14649. OutChannel->HTTP2ClientOutChannel::~HTTP2ClientOutChannel();
  14650. goto AbortAndExit;
  14651. }
  14652. EndpointReceiver->SetUpperChannel(OutChannel);
  14653. OutChannel->SetLowerChannel(EndpointReceiver);
  14654. if (UseWinHttp)
  14655. WinHttpConnection->SetTopChannel(OutChannel);
  14656. else
  14657. RawChannel->SetTopChannel(OutChannel);
  14658. PingReceiver->SetTopChannel(OutChannel);
  14659. EndpointReceiver->SetTopChannel(OutChannel);
  14660. ASSERT(RpcStatus == RPC_S_OK);
  14661. *ReturnOutChannel = OutChannel;
  14662. goto CleanupAndExit;
  14663. AbortAndExit:
  14664. if (EndpointReceiverNeedsCleanup)
  14665. {
  14666. EndpointReceiver->Abort(RpcStatus);
  14667. EndpointReceiver->FreeObject();
  14668. }
  14669. else if (PingReceiverNeedsCleanup)
  14670. {
  14671. PingReceiver->Abort(RpcStatus);
  14672. PingReceiver->FreeObject();
  14673. }
  14674. else if (UseWinHttp)
  14675. {
  14676. if (WinHttpConnectionNeedsCleanup)
  14677. {
  14678. WinHttpConnection->Abort(RpcStatus);
  14679. WinHttpConnection->FreeObject();
  14680. }
  14681. }
  14682. else if (RawChannelNeedsCleanup)
  14683. {
  14684. RawChannel->Abort(RpcStatus);
  14685. RawChannel->FreeObject();
  14686. }
  14687. else if (RawConnectionNeedsCleanup)
  14688. {
  14689. RawConnection->RealAbort();
  14690. }
  14691. if (MemoryBlock)
  14692. delete [] MemoryBlock;
  14693. CleanupAndExit:
  14694. return RpcStatus;
  14695. }
  14696. RPC_STATUS HTTP2ClientVirtualConnection::InitializeRawConnection (
  14697. IN OUT WS_HTTP2_CONNECTION *RawConnection,
  14698. IN HTTPResolverHint *Hint,
  14699. IN BOOL HintWasInitialized,
  14700. IN ULONG CallTimeout
  14701. )
  14702. /*++
  14703. Routine Description:
  14704. Initialize a raw client connection
  14705. Arguments:
  14706. RawConnection - memory for the connection. It is uninitialized
  14707. Hint - the resolver hint
  14708. HintWasInitialized - true if the hint was initialized on input
  14709. CallTimeout - the timeout for the operation
  14710. Return Value:
  14711. RPC_S_OK or other RPC_S_* errors for error
  14712. --*/
  14713. {
  14714. RPC_STATUS RpcStatus;
  14715. RPC_CHAR *ConnectionTargetName;
  14716. USHORT PortToUse;
  14717. RawConnection->Initialize();
  14718. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  14719. // initialize raw connection
  14720. if (Hint->AccessType == rpcpatHTTPProxy)
  14721. {
  14722. ConnectionTargetName = new RPC_CHAR [RpcpStringLengthA(Hint->HTTPProxy) + 2];
  14723. if (ConnectionTargetName == NULL)
  14724. {
  14725. RpcStatus = RPC_S_OUT_OF_MEMORY;
  14726. return RpcStatus;
  14727. }
  14728. FullAnsiToUnicode(Hint->HTTPProxy, ConnectionTargetName);
  14729. PortToUse = Hint->HTTPProxyPort;
  14730. }
  14731. else
  14732. {
  14733. ASSERT(Hint->AccessType == rpcpatDirect);
  14734. ConnectionTargetName = new RPC_CHAR [RpcpStringLengthA(Hint->RpcProxy) + 1];
  14735. if (ConnectionTargetName == NULL)
  14736. {
  14737. RpcStatus = RPC_S_OUT_OF_MEMORY;
  14738. return RpcStatus;
  14739. }
  14740. FullAnsiToUnicode(Hint->RpcProxy, ConnectionTargetName);
  14741. PortToUse = Hint->RpcProxyPort;
  14742. }
  14743. RpcStatus = TCPOrHTTP_Open(RawConnection,
  14744. ConnectionTargetName,
  14745. PortToUse,
  14746. ConnectionTimeout,
  14747. 0, // SendBufferSize
  14748. 0, // RecvBufferSize
  14749. Hint,
  14750. HintWasInitialized,
  14751. CallTimeout,
  14752. TRUE, // fHTTP2Open
  14753. NULL // IsValidMachineFn
  14754. );
  14755. delete [] ConnectionTargetName;
  14756. return RpcStatus;
  14757. }
  14758. BOOL HTTP2ClientVirtualConnection::IsInChannelKeepAlive (
  14759. IN BOOL IsReplacementChannel
  14760. )
  14761. /*++
  14762. Routine Description:
  14763. Checks whether the an in channel supports keep alives.
  14764. Which channel depends on the arguments - see below.
  14765. Arguments:
  14766. IsReplacementInChannel - if non-zero, this is a replacement
  14767. channel and the non-default channel will be checked. If 0,
  14768. this is a first channel, and the zero'th channel will be
  14769. checked.
  14770. Return Value:
  14771. non-zero - the channel supports keep alives
  14772. 0 - the channel doesn't support keep alives
  14773. --*/
  14774. {
  14775. HTTP2ClientInChannel *InChannel;
  14776. BOOL IsKeepAlive;
  14777. HTTP2ChannelPointer *InChannelPtr;
  14778. if (IsReplacementChannel)
  14779. InChannelPtr = &InChannels[GetNonDefaultInChannelSelector()];
  14780. else
  14781. InChannelPtr = &InChannels[0];
  14782. InChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  14783. // nobody can abort the connection here
  14784. ASSERT (InChannel != NULL);
  14785. IsKeepAlive = InChannel->IsKeepAlive();
  14786. InChannelPtr->UnlockChannelPointer();
  14787. return IsKeepAlive;
  14788. }
  14789. BOOL HTTP2ClientVirtualConnection::IsOutChannelKeepAlive (
  14790. IN BOOL IsReplacementChannel
  14791. )
  14792. /*++
  14793. Routine Description:
  14794. Checks whether an out channel supports keep alives
  14795. Which channel depends on the arguments - see below.
  14796. Arguments:
  14797. IsReplacementInChannel - if non-zero, this is a replacement
  14798. channel and the non-default channel will be checked. If 0,
  14799. this is a first channel, and the zero'th channel will be
  14800. checked.
  14801. Return Value:
  14802. non-zero - the channel supports keep alives
  14803. 0 - the channel doesn't support keep alives
  14804. --*/
  14805. {
  14806. HTTP2ClientOutChannel *OutChannel;
  14807. BOOL IsKeepAlive;
  14808. HTTP2ChannelPointer *OutChannelPtr;
  14809. if (IsReplacementChannel)
  14810. OutChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  14811. else
  14812. OutChannelPtr = &OutChannels[0];
  14813. OutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  14814. // nobody can abort the connection here
  14815. ASSERT (OutChannel != NULL);
  14816. IsKeepAlive = OutChannel->IsKeepAlive();
  14817. OutChannelPtr->UnlockChannelPointer();
  14818. return IsKeepAlive;
  14819. }
  14820. ULONG HTTP2ClientVirtualConnection::GetInChannelChosenScheme (
  14821. IN BOOL IsReplacementChannel
  14822. )
  14823. /*++
  14824. Routine Description:
  14825. Gets the chosen scheme for the an in channel
  14826. Which channel depends on the arguments - see below.
  14827. Arguments:
  14828. IsReplacementInChannel - if non-zero, this is a replacement
  14829. channel and the non-default channel will be checked. If 0,
  14830. this is a first channel, and the zero'th channel will be
  14831. checked.
  14832. Return Value:
  14833. Chosen scheme
  14834. --*/
  14835. {
  14836. HTTP2ClientInChannel *InChannel;
  14837. ULONG ChosenScheme;
  14838. HTTP2ChannelPointer *InChannelPtr;
  14839. if (IsReplacementChannel)
  14840. InChannelPtr = &InChannels[GetNonDefaultInChannelSelector()];
  14841. else
  14842. InChannelPtr = &InChannels[0];
  14843. InChannel = (HTTP2ClientInChannel *)InChannelPtr->LockChannelPointer();
  14844. // nobody can abort the connection here
  14845. ASSERT (InChannel != NULL);
  14846. ChosenScheme = InChannel->GetChosenAuthScheme();
  14847. InChannelPtr->UnlockChannelPointer();
  14848. return ChosenScheme;
  14849. }
  14850. ULONG HTTP2ClientVirtualConnection::GetOutChannelChosenScheme (
  14851. IN BOOL IsReplacementChannel
  14852. )
  14853. /*++
  14854. Routine Description:
  14855. Gets the chosen scheme for an out channel
  14856. Which channel depends on the arguments - see below.
  14857. Arguments:
  14858. IsReplacementInChannel - if non-zero, this is a replacement
  14859. channel and the non-default channel will be checked. If 0,
  14860. this is a first channel, and the zero'th channel will be
  14861. checked.
  14862. Return Value:
  14863. Chosen scheme
  14864. --*/
  14865. {
  14866. HTTP2ClientOutChannel *OutChannel;
  14867. ULONG ChosenScheme;
  14868. HTTP2ChannelPointer *OutChannelPtr;
  14869. if (IsReplacementChannel)
  14870. OutChannelPtr = &OutChannels[GetNonDefaultOutChannelSelector()];
  14871. else
  14872. OutChannelPtr = &OutChannels[0];
  14873. OutChannel = (HTTP2ClientOutChannel *)OutChannelPtr->LockChannelPointer();
  14874. // nobody can abort the connection here
  14875. ASSERT (OutChannel != NULL);
  14876. ChosenScheme = OutChannel->GetChosenAuthScheme();
  14877. OutChannelPtr->UnlockChannelPointer();
  14878. return ChosenScheme;
  14879. }
  14880. BOOL HTTP2ClientVirtualConnection::IsInChannelPositiveWithWait (
  14881. void
  14882. )
  14883. /*++
  14884. Routine Description:
  14885. Checks if the in channel has come in with positive result. If
  14886. not, it waits a bit and tries again. If not again, return FALSE.
  14887. Arguments:
  14888. Return Value:
  14889. non-zero if the in channel came in positive.
  14890. 0 otherwise.
  14891. --*/
  14892. {
  14893. if ((InOpenStatus == RPC_S_OK)
  14894. || (InOpenStatus == RPC_P_AUTH_NEEDED))
  14895. return TRUE;
  14896. Sleep(100);
  14897. return ((InOpenStatus == RPC_S_OK)
  14898. || (InOpenStatus == RPC_P_AUTH_NEEDED));
  14899. }
  14900. /*********************************************************************
  14901. Switching Layer
  14902. *********************************************************************/
  14903. RPC_STATUS
  14904. RPC_ENTRY
  14905. HTTP_SyncRecv(
  14906. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  14907. OUT BUFFER *pBuffer,
  14908. OUT PUINT pBufferLength,
  14909. IN DWORD dwTimeout
  14910. )
  14911. /*++
  14912. Routine Description:
  14913. Perform a sync recv on an HTTP connection. Part of the HTTP switching
  14914. layer between old mode and new mode.
  14915. Arguments:
  14916. ThisConnection - transport connection
  14917. Buffer - if successful, points to a buffer containing the next PDU.
  14918. BufferLength - if successful, contains the length of the message.
  14919. Timeout - the amount of time to wait for the receive. If -1, we wait
  14920. infinitely.
  14921. Return Value:
  14922. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  14923. --*/
  14924. {
  14925. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  14926. HTTP2VirtualConnection *VirtualConnection;
  14927. RPC_STATUS RpcStatus;
  14928. if (BaseObject->id == HTTP)
  14929. {
  14930. return WS_SyncRecv(ThisConnection,
  14931. pBuffer,
  14932. pBufferLength,
  14933. dwTimeout
  14934. );
  14935. }
  14936. else
  14937. {
  14938. ASSERT(BaseObject->id == HTTPv2);
  14939. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  14940. RpcStatus = VirtualConnection->SyncRecv((BYTE **)pBuffer,
  14941. (ULONG *)pBufferLength,
  14942. dwTimeout);
  14943. VALIDATE(RpcStatus)
  14944. {
  14945. RPC_S_OK,
  14946. RPC_S_OUT_OF_MEMORY,
  14947. RPC_S_OUT_OF_RESOURCES,
  14948. RPC_P_RECEIVE_FAILED,
  14949. RPC_S_CALL_CANCELLED,
  14950. RPC_P_SEND_FAILED,
  14951. RPC_P_CONNECTION_SHUTDOWN,
  14952. RPC_P_TIMEOUT
  14953. }
  14954. CORRUPTION_VALIDATE
  14955. {
  14956. RPC_S_PROTOCOL_ERROR
  14957. } CORRUPTION_END_VALIDATE;
  14958. return RpcStatus;
  14959. }
  14960. }
  14961. RPC_STATUS
  14962. RPC_ENTRY
  14963. HTTP_Abort (
  14964. IN RPC_TRANSPORT_CONNECTION Connection
  14965. )
  14966. /*++
  14967. Routine Description:
  14968. Aborts an HTTP connection. Part of the HTTP switching
  14969. layer between old mode and new mode.
  14970. Arguments:
  14971. Connection - transport connection
  14972. Return Value:
  14973. RPC_S_OK
  14974. --*/
  14975. {
  14976. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) Connection;
  14977. HTTP2VirtualConnection *VirtualConnection;
  14978. if (BaseObject->id == HTTP)
  14979. {
  14980. return WS_Abort(Connection);
  14981. }
  14982. else
  14983. {
  14984. ASSERT(BaseObject->id == HTTPv2);
  14985. VirtualConnection = (HTTP2VirtualConnection *)Connection;
  14986. if ((VirtualConnection->type & TYPE_MASK) == CLIENT)
  14987. {
  14988. ((HTTP2ClientVirtualConnection *)VirtualConnection)->HTTP2ClientVirtualConnection::Abort();
  14989. }
  14990. else
  14991. {
  14992. ASSERT((VirtualConnection->type & TYPE_MASK) == SERVER);
  14993. ((HTTP2ServerVirtualConnection *)VirtualConnection)->HTTP2ServerVirtualConnection::Abort();
  14994. }
  14995. return RPC_S_OK;
  14996. }
  14997. }
  14998. RPC_STATUS
  14999. RPC_ENTRY
  15000. HTTP_Close (
  15001. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15002. IN BOOL fDontFlush
  15003. )
  15004. /*++
  15005. Routine Description:
  15006. Aborts an HTTP connection. Part of the HTTP switching
  15007. layer between old mode and new mode.
  15008. Arguments:
  15009. ThisConnection - transport connection
  15010. DontFlush - non-zero if all buffers need to be flushed
  15011. before closing the connection. Zero otherwise.
  15012. Return Value:
  15013. RPC_S_OK
  15014. --*/
  15015. {
  15016. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15017. HTTP2VirtualConnection *VirtualConnection;
  15018. RPC_STATUS RpcStatus;
  15019. LOG_FN_OPERATION_ENTRY(HTTP2LOG_OPERATION_CLOSE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)ThisConnection);
  15020. #if DBG
  15021. // verify the list is still ok
  15022. TransportProtocol::AssertProtocolListIntegrity(BaseObject);
  15023. #endif // DBG
  15024. if (BaseObject->id == HTTP)
  15025. {
  15026. RpcStatus = WS_Close(ThisConnection,
  15027. fDontFlush
  15028. );
  15029. }
  15030. else if (BaseObject->id == INVALID_PROTOCOL_ID)
  15031. {
  15032. // object was never completely initialized - just return
  15033. RpcStatus = RPC_S_OK;
  15034. }
  15035. else
  15036. {
  15037. ASSERT(BaseObject->id == HTTPv2);
  15038. // the object may have been destroyed by now - cannot use
  15039. // virtual functions. Determine statically the type
  15040. // and call the function to cleanup (it knows how to
  15041. // deal with destroyed objects)
  15042. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15043. if ((VirtualConnection->type & TYPE_MASK) == CLIENT)
  15044. {
  15045. ((HTTP2ClientVirtualConnection *)VirtualConnection)->HTTP2ClientVirtualConnection::Close(fDontFlush);
  15046. }
  15047. else
  15048. {
  15049. ASSERT((VirtualConnection->type & TYPE_MASK) == SERVER);
  15050. ((HTTP2ServerVirtualConnection *)VirtualConnection)->HTTP2ServerVirtualConnection::Close(fDontFlush);
  15051. }
  15052. RpcStatus = RPC_S_OK;
  15053. }
  15054. LOG_FN_OPERATION_EXIT(HTTP2LOG_OPERATION_CLOSE, HTTP2LOG_OT_CALLBACK, (ULONG_PTR)BaseObject->id);
  15055. return RpcStatus;
  15056. }
  15057. RPC_STATUS
  15058. RPC_ENTRY
  15059. HTTP_Send(
  15060. RPC_TRANSPORT_CONNECTION ThisConnection,
  15061. UINT Length,
  15062. BUFFER Buffer,
  15063. PVOID SendContext
  15064. )
  15065. /*++
  15066. Routine Description:
  15067. Does a send on an HTTP connection. Part of the HTTP switching
  15068. layer between old mode and new mode.
  15069. Arguments:
  15070. ThisConnection - The connection to send the data on.
  15071. Length - The length of the data to send.
  15072. Buffer - The data to send.
  15073. SendContext - A buffer to use as the HTTP2SendContext for
  15074. this operation.
  15075. Return Value:
  15076. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  15077. --*/
  15078. {
  15079. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15080. HTTP2VirtualConnection *VirtualConnection;
  15081. if (BaseObject->id == HTTP)
  15082. {
  15083. return CO_Send(ThisConnection,
  15084. Length,
  15085. Buffer,
  15086. SendContext
  15087. );
  15088. }
  15089. else
  15090. {
  15091. ASSERT(BaseObject->id == HTTPv2);
  15092. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15093. return VirtualConnection->Send(Length,
  15094. Buffer,
  15095. SendContext
  15096. );
  15097. }
  15098. }
  15099. RPC_STATUS
  15100. RPC_ENTRY
  15101. HTTP_Recv(
  15102. RPC_TRANSPORT_CONNECTION ThisConnection
  15103. )
  15104. /*++
  15105. Routine Description:
  15106. Does a receive on an HTTP connection. Part of the HTTP switching
  15107. layer between old mode and new mode.
  15108. Arguments:
  15109. ThisConnection - A connection without a read pending on it.
  15110. Return Value:
  15111. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  15112. --*/
  15113. {
  15114. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15115. HTTP2VirtualConnection *VirtualConnection;
  15116. if (BaseObject->id == HTTP)
  15117. {
  15118. return CO_Recv(ThisConnection);
  15119. }
  15120. else
  15121. {
  15122. ASSERT(BaseObject->id == HTTPv2);
  15123. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15124. return VirtualConnection->Receive();
  15125. }
  15126. }
  15127. RPC_STATUS
  15128. RPC_ENTRY
  15129. HTTP_SyncSend(
  15130. IN RPC_TRANSPORT_CONNECTION Connection,
  15131. IN UINT BufferLength,
  15132. IN BUFFER Buffer,
  15133. IN BOOL fDisableShutdownCheck,
  15134. IN BOOL fDisableCancelCheck,
  15135. ULONG Timeout
  15136. )
  15137. /*++
  15138. Routine Description:
  15139. Does a sync send on an HTTP connection. Part of the HTTP switching
  15140. layer between old mode and new mode.
  15141. Arguments:
  15142. Connection - The connection to send on.
  15143. BufferLength - The size of the buffer.
  15144. Buffer - The data to sent.
  15145. fDisableShutdownCheck - Normally FALSE, when true this disables
  15146. the transport check for async shutdown PDUs.
  15147. fDisableCancelCheck - runtime indicates no cancel
  15148. will be attempted on this send. Can be used
  15149. as optimization hint by the transport
  15150. Timeout - send timeout (call timeout)
  15151. Return Value:
  15152. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  15153. --*/
  15154. {
  15155. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) Connection;
  15156. HTTP2VirtualConnection *VirtualConnection;
  15157. RPC_STATUS RpcStatus;
  15158. if (BaseObject->id == HTTP)
  15159. {
  15160. RpcStatus = WS_SyncSend(Connection,
  15161. BufferLength,
  15162. Buffer,
  15163. fDisableShutdownCheck,
  15164. fDisableCancelCheck,
  15165. Timeout
  15166. );
  15167. }
  15168. else
  15169. {
  15170. ASSERT(BaseObject->id == HTTPv2);
  15171. VirtualConnection = (HTTP2VirtualConnection *)Connection;
  15172. RpcStatus = VirtualConnection->SyncSend(BufferLength,
  15173. Buffer,
  15174. fDisableShutdownCheck,
  15175. fDisableCancelCheck,
  15176. Timeout
  15177. );
  15178. }
  15179. VALIDATE(RpcStatus)
  15180. {
  15181. RPC_S_OK,
  15182. RPC_S_OUT_OF_MEMORY,
  15183. RPC_S_OUT_OF_RESOURCES,
  15184. RPC_P_RECEIVE_FAILED,
  15185. RPC_S_CALL_CANCELLED,
  15186. RPC_P_SEND_FAILED,
  15187. RPC_P_CONNECTION_SHUTDOWN,
  15188. RPC_P_TIMEOUT
  15189. } END_VALIDATE;
  15190. return RpcStatus;
  15191. }
  15192. RPC_STATUS
  15193. RPC_ENTRY
  15194. HTTP_TurnOnOffKeepAlives (
  15195. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15196. IN BOOL TurnOn,
  15197. IN BOOL bProtectIO,
  15198. IN KEEPALIVE_TIMEOUT_UNITS Units,
  15199. IN OUT KEEPALIVE_TIMEOUT KATime,
  15200. IN ULONG KAInterval OPTIONAL
  15201. )
  15202. /*++
  15203. Routine Description:
  15204. Turns on keep alives for an HTTP connection. Part of the HTTP switching
  15205. layer between old mode and new mode.
  15206. Arguments:
  15207. ThisConnection - The connection to turn keep alives on on.
  15208. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  15209. are turned off.
  15210. bProtectIO - non-zero if IO needs to be protected against async close
  15211. of the connection.
  15212. Units - in what units is KATime
  15213. KATime - how much to wait before turning on keep alives
  15214. KAInterval - the interval between keep alives
  15215. Return Value:
  15216. RPC_S_OK or RPC_S_* / Win32 errors on failure
  15217. Note:
  15218. If we use it on the server, we must protect
  15219. the connection against async aborts.
  15220. --*/
  15221. {
  15222. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15223. HTTP2VirtualConnection *VirtualConnection;
  15224. if (BaseObject->id == HTTP)
  15225. {
  15226. return WS_TurnOnOffKeepAlives(ThisConnection,
  15227. TurnOn,
  15228. bProtectIO,
  15229. Units,
  15230. KATime,
  15231. KAInterval
  15232. );
  15233. }
  15234. else
  15235. {
  15236. ASSERT(BaseObject->id == HTTPv2);
  15237. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15238. // don't bother if the connection is aborted. Besides shorter
  15239. // execution, this avoids trouble where we try to perform the
  15240. // operation on an aborted connection and we run into all
  15241. // sorts of problems.
  15242. if (VirtualConnection->IsAborted())
  15243. return RPC_S_OK;
  15244. return VirtualConnection->TurnOnOffKeepAlives(TurnOn,
  15245. bProtectIO,
  15246. FALSE, // IsFromUpcall
  15247. Units,
  15248. KATime,
  15249. KAInterval
  15250. );
  15251. }
  15252. }
  15253. RPC_STATUS
  15254. RPC_ENTRY
  15255. HTTP_QueryClientAddress (
  15256. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15257. OUT RPC_CHAR **pNetworkAddress
  15258. )
  15259. /*++
  15260. Routine Description:
  15261. Returns the IP address of the client on a connection as a string.
  15262. Arguments:
  15263. NetworkAddress - Will contain string on success.
  15264. Return Value:
  15265. RPC_S_OK or other RPC_S_* errors for error
  15266. --*/
  15267. {
  15268. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15269. HTTP2VirtualConnection *VirtualConnection;
  15270. if (BaseObject->id == HTTP)
  15271. {
  15272. return TCP_QueryClientAddress(ThisConnection,
  15273. pNetworkAddress
  15274. );
  15275. }
  15276. else
  15277. {
  15278. ASSERT(BaseObject->id == HTTPv2);
  15279. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15280. return VirtualConnection->QueryClientAddress(pNetworkAddress);
  15281. }
  15282. }
  15283. RPC_STATUS
  15284. RPC_ENTRY
  15285. HTTP_QueryLocalAddress (
  15286. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15287. IN OUT void *Buffer,
  15288. IN OUT unsigned long *BufferSize,
  15289. OUT unsigned long *AddressFormat
  15290. )
  15291. /*++
  15292. Routine Description:
  15293. Returns the local IP address of a connection.
  15294. Arguments:
  15295. Buffer - The buffer that will receive the output address
  15296. BufferSize - the size of the supplied Buffer on input. On output the
  15297. number of bytes written to the buffer. If the buffer is too small
  15298. to receive all the output data, ERROR_MORE_DATA is returned,
  15299. nothing is written to the buffer, and BufferSize is set to
  15300. the size of the buffer needed to return all the data.
  15301. AddressFormat - a constant indicating the format of the returned address.
  15302. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  15303. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  15304. Return Value:
  15305. RPC_S_OK or other RPC_S_* errors for error
  15306. --*/
  15307. {
  15308. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15309. HTTP2VirtualConnection *VirtualConnection;
  15310. if (BaseObject->id == HTTP)
  15311. {
  15312. return TCP_QueryLocalAddress(ThisConnection,
  15313. Buffer,
  15314. BufferSize,
  15315. AddressFormat
  15316. );
  15317. }
  15318. else
  15319. {
  15320. ASSERT(BaseObject->id == HTTPv2);
  15321. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15322. return VirtualConnection->QueryLocalAddress(Buffer,
  15323. BufferSize,
  15324. AddressFormat
  15325. );
  15326. }
  15327. }
  15328. RPC_STATUS
  15329. RPC_ENTRY
  15330. HTTP_QueryClientId(
  15331. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15332. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  15333. )
  15334. /*++
  15335. Routine Description:
  15336. For secure protocols (which TCP/IP is not) this is supposed to
  15337. give an ID which will be shared by all clients from the same
  15338. process. This prevents one user from grabbing another users
  15339. association group and using their context handles.
  15340. Since TCP/IP is not secure we return the IP address of the
  15341. client machine. This limits the attacks to other processes
  15342. running on the client machine which is better than nothing.
  15343. Arguments:
  15344. ClientProcess - Transport identification of the "client".
  15345. Return Value:
  15346. RPC_S_OK or other RPC_S_* errors for error
  15347. --*/
  15348. {
  15349. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15350. HTTP2VirtualConnection *VirtualConnection;
  15351. if (BaseObject->id == HTTP)
  15352. {
  15353. return TCP_QueryClientId(ThisConnection,
  15354. ClientProcess
  15355. );
  15356. }
  15357. else
  15358. {
  15359. ASSERT(BaseObject->id == HTTPv2);
  15360. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15361. return VirtualConnection->QueryClientId(ClientProcess);
  15362. }
  15363. }
  15364. RPC_STATUS
  15365. RPC_ENTRY
  15366. HTTP_QueryClientIpAddress (
  15367. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  15368. IN OUT RPC_CLIENT_IP_ADDRESS *ClientIpAddress
  15369. )
  15370. /*++
  15371. Routine Description:
  15372. Returns the IP address of the client on a connection as a SOCKADDR.
  15373. Arguments:
  15374. ThisConnection - The server connection of interest.
  15375. ClientIpAddress - the buffer to store the address to.
  15376. Return Value:
  15377. RPC_S_OK or other RPC_S_* errors for error
  15378. --*/
  15379. {
  15380. BASE_ASYNC_OBJECT *BaseObject = (BASE_ASYNC_OBJECT *) ThisConnection;
  15381. HTTP2VirtualConnection *VirtualConnection;
  15382. if (BaseObject->id == HTTP)
  15383. {
  15384. return TCP_QueryClientIpAddress(ThisConnection,
  15385. ClientIpAddress
  15386. );
  15387. }
  15388. else
  15389. {
  15390. ASSERT(BaseObject->id == HTTPv2);
  15391. VirtualConnection = (HTTP2VirtualConnection *)ThisConnection;
  15392. return VirtualConnection->QueryClientIpAddress(ClientIpAddress);
  15393. }
  15394. }
  15395. /*********************************************************************
  15396. HTTP Transport Interface
  15397. *********************************************************************/
  15398. const int HTTPClientConnectionSize = max(sizeof(WS_CLIENT_CONNECTION), sizeof(WS_SAN_CLIENT_CONNECTION));
  15399. const int HTTP2ClientConnectionSize = sizeof(HTTP2ClientVirtualConnection);
  15400. const int HTTPServerConnectionSize = max(sizeof(WS_CONNECTION), sizeof(WS_SAN_CONNECTION));
  15401. const int HTTP2ServerConnectionSize = max(sizeof(HTTP2ServerVirtualConnection), sizeof(WS_HTTP2_INITIAL_CONNECTION));
  15402. const RPC_CONNECTION_TRANSPORT
  15403. HTTP_TransportInterface =
  15404. {
  15405. RPC_TRANSPORT_INTERFACE_VERSION,
  15406. HTTP_TOWER_ID,
  15407. HTTP_ADDRESS_ID,
  15408. RPC_STRING_LITERAL("ncacn_http"),
  15409. "593",
  15410. COMMON_ProcessCalls,
  15411. COMMON_StartPnpNotifications,
  15412. COMMON_ListenForPNPNotifications,
  15413. COMMON_TowerConstruct,
  15414. COMMON_TowerExplode,
  15415. COMMON_PostRuntimeEvent,
  15416. FALSE,
  15417. WS_GetNetworkAddressVector,
  15418. sizeof(WS_ADDRESS),
  15419. max(HTTPClientConnectionSize, HTTP2ClientConnectionSize),
  15420. max(HTTPServerConnectionSize, HTTP2ServerConnectionSize),
  15421. sizeof(HTTP2SendContext),
  15422. sizeof(HTTPResolverHint),
  15423. HTTP_MAX_SEND,
  15424. HTTP_Initialize,
  15425. 0, // InitComplete,
  15426. HTTP_Open,
  15427. 0, // No SendRecv on winsock
  15428. HTTP_SyncRecv,
  15429. HTTP_Abort,
  15430. HTTP_Close,
  15431. HTTP_Send,
  15432. HTTP_Recv,
  15433. HTTP_SyncSend,
  15434. HTTP_TurnOnOffKeepAlives,
  15435. HTTP_ServerListen,
  15436. WS_ServerAbortListen,
  15437. COMMON_ServerCompleteListen,
  15438. HTTP_QueryClientAddress,
  15439. HTTP_QueryLocalAddress,
  15440. HTTP_QueryClientId,
  15441. HTTP_QueryClientIpAddress,
  15442. 0, // Impersonate
  15443. 0, // Revert
  15444. HTTP_FreeResolverHint,
  15445. HTTP_CopyResolverHint,
  15446. HTTP_CompareResolverHint,
  15447. HTTP_SetLastBufferToFree
  15448. };
  15449. /*********************************************************************
  15450. HTTP2ProxyServerSideChannel
  15451. *********************************************************************/
  15452. RPC_STATUS HTTP2ProxyServerSideChannel::InitializeRawConnection (
  15453. IN RPC_CHAR *ServerName,
  15454. IN USHORT ServerPort,
  15455. IN ULONG ConnectionTimeout,
  15456. IN I_RpcProxyIsValidMachineFn IsValidMachineFn
  15457. )
  15458. /*++
  15459. Routine Description:
  15460. Initializes a raw connection.
  15461. Arguments:
  15462. ServerName - the server to connect to.
  15463. ServerPort - which port on that server to use
  15464. ConnectionTimeout - the connection timeout to use.
  15465. IsValidMachineFn - a callback function to verify if the
  15466. target machine/port are not blocked
  15467. Return Value:
  15468. RPC_S_OK or RPC_S_* for error
  15469. --*/
  15470. {
  15471. RPC_STATUS RpcStatus;
  15472. HTTPResolverHint DummyHint;
  15473. RpcStatus = TCPOrHTTP_Open(RawConnection,
  15474. ServerName,
  15475. ServerPort,
  15476. ConnectionTimeout,
  15477. 0, // SendBufferSize
  15478. 0, // RecvBufferSize
  15479. &DummyHint,
  15480. FALSE, // HintWasInitialized
  15481. 10 * 60 * 60, // 10 minutes
  15482. TRUE, // fHTTP2Open
  15483. IsValidMachineFn
  15484. );
  15485. return RpcStatus;
  15486. }
  15487. /*********************************************************************
  15488. HTTP2TimeoutTargetConnection
  15489. *********************************************************************/
  15490. RPC_STATUS HTTP2TimeoutTargetConnection::SetTimeout (
  15491. IN ULONG Timeout,
  15492. IN TimerContext *pTimer
  15493. )
  15494. /*++
  15495. Routine Description:
  15496. Called to setup a one time timer. Caller must make
  15497. sure this function is synchronized with CancelTimeout and
  15498. must make sure we don't schedule a timer behind an aborting
  15499. thread (i.e. a timer fires after the object goes away).
  15500. Arguments:
  15501. Timeout - interval before the timer fires
  15502. pTimer - which timer do we refer to.
  15503. Return Value:
  15504. RPC_S_OK or RPC_S_* error
  15505. --*/
  15506. {
  15507. BOOL Result;
  15508. VerifyValidTimer(pTimer);
  15509. VerifyTimerNotSet(pTimer);
  15510. Result = CreateTimerQueueTimer(&(pTimer->Handle),
  15511. NULL,
  15512. HTTP2TimeoutTimerCallback,
  15513. pTimer,
  15514. Timeout, // time to first fire
  15515. 0, // periodic interval
  15516. WT_EXECUTELONGFUNCTION
  15517. );
  15518. if (Result == FALSE)
  15519. return RPC_S_OUT_OF_MEMORY;
  15520. return RPC_S_OK;
  15521. }
  15522. void HTTP2TimeoutTargetConnection::CancelTimeout (
  15523. IN TimerContext *pTimer
  15524. )
  15525. /*++
  15526. Routine Description:
  15527. Called to cancel a timer. The function will not return until
  15528. the timer callbacks have been drained. Caller must ensure
  15529. that this method is synchronized with SetTimeout
  15530. Arguments:
  15531. pTimer - which timer do we refer to.
  15532. Return Value:
  15533. --*/
  15534. {
  15535. HANDLE LocalTimerHandle;
  15536. BOOL Result;
  15537. unsigned int Retries = 0;
  15538. VerifyValidTimer(pTimer);
  15539. LocalTimerHandle = InterlockedExchangePointer(&(pTimer->Handle), NULL);
  15540. // if the timer already fired there is nothing to do here.
  15541. if (LocalTimerHandle == NULL)
  15542. return;
  15543. do
  15544. {
  15545. Result = DeleteTimerQueueTimer(NULL,
  15546. LocalTimerHandle,
  15547. INVALID_HANDLE_VALUE // tell the timer function to wait for all callbacks
  15548. // to complete before returning
  15549. );
  15550. //
  15551. // This cannot fail unless we give it invalid parameters or
  15552. // we are out of memory. Retry on out of memory since there is nothing we can do.
  15553. // If after a few attempts we still fail, we need to halt to avoid a later AV.
  15554. //
  15555. // From Rob Earhart:
  15556. // 485863 covers one of the allocs... the entire module is pretty bad code;
  15557. // I'm planning to just replace it (and the API, too).
  15558. //
  15559. if (!Result)
  15560. {
  15561. ASSERT(GetLastError() == ERROR_NOT_ENOUGH_MEMORY);
  15562. DbgPrint("RPC: DeleteTimerQueueTimer failed: %d\n", GetLastError());
  15563. Sleep(10);
  15564. }
  15565. Retries++;
  15566. }
  15567. while (!Result && Retries < 10);
  15568. if (!Result)
  15569. {
  15570. DbgPrint("RPC: DeleteTimerQueueTimer repeatedly failed - execution can't proceed.\n");
  15571. DbgBreakPoint();
  15572. }
  15573. }
  15574. /*********************************************************************
  15575. HTTP2ProxyVirtualConnection
  15576. *********************************************************************/
  15577. RPC_STATUS HTTP2ProxyVirtualConnection::SendComplete (
  15578. IN RPC_STATUS EventStatus,
  15579. IN OUT HTTP2SendContext *SendContext,
  15580. IN int ChannelId
  15581. )
  15582. /*++
  15583. Routine Description:
  15584. Called by lower layers to indicate send complete.
  15585. Arguments:
  15586. EventStatus - status of the operation
  15587. SendContext - the context for the send complete
  15588. ChannelId - which channel completed the operation
  15589. Return Value:
  15590. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  15591. be hidden from the runtime.
  15592. RPC_S_OK if the packet was processed successfully.
  15593. RPC_S_* error if there was an error while processing the
  15594. packet.
  15595. --*/
  15596. {
  15597. HTTP2ChannelPointer *ChannelPtr;
  15598. HTTP2InProxyInChannel *InProxyInChannel;
  15599. HTTP2OutProxyInChannel *OutProxyInChannel;
  15600. BOOL LocalIsInProxy;
  15601. BOOL IssueAck;
  15602. ULONG BytesReceivedForAck;
  15603. ULONG WindowForAck;
  15604. BOOL UnlockPointer;
  15605. VerifyValidChannelId(ChannelId);
  15606. if ((EventStatus == RPC_S_OK)
  15607. && (SendContext->TrafficType == http2ttData))
  15608. {
  15609. ChannelPtr = MapSendContextUserDataToChannelPtr(SendContext->UserData);
  15610. if (ChannelPtr)
  15611. {
  15612. UnlockPointer = FALSE;
  15613. IssueAck = FALSE;
  15614. LocalIsInProxy = IsInProxy();
  15615. if (LocalIsInProxy)
  15616. {
  15617. InProxyInChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  15618. if (InProxyInChannel)
  15619. {
  15620. UnlockPointer = TRUE;
  15621. InProxyInChannel->BytesConsumedNotification (SendContext->maxWriteBuffer,
  15622. FALSE, // OwnsMutex
  15623. &IssueAck,
  15624. &BytesReceivedForAck,
  15625. &WindowForAck
  15626. );
  15627. }
  15628. }
  15629. else
  15630. {
  15631. OutProxyInChannel = (HTTP2OutProxyInChannel *)ChannelPtr->LockChannelPointer();
  15632. if (OutProxyInChannel)
  15633. {
  15634. UnlockPointer = TRUE;
  15635. OutProxyInChannel->BytesConsumedNotification (SendContext->maxWriteBuffer,
  15636. FALSE, // OwnsMutex
  15637. &IssueAck,
  15638. &BytesReceivedForAck,
  15639. &WindowForAck
  15640. );
  15641. }
  15642. }
  15643. if (IssueAck)
  15644. {
  15645. // we need to issue a flow control ack to the peer. InProxy uses
  15646. // forwarding, out proxy sends ack directly
  15647. if (LocalIsInProxy)
  15648. {
  15649. EventStatus = InProxyInChannel->ForwardFlowControlAck(
  15650. BytesReceivedForAck,
  15651. WindowForAck
  15652. );
  15653. }
  15654. else
  15655. {
  15656. EventStatus = OutProxyInChannel->ForwardFlowControlAck(
  15657. BytesReceivedForAck,
  15658. WindowForAck
  15659. );
  15660. }
  15661. #if DBG_ERROR
  15662. DbgPrint("%s proxy issuing flow control ack: %d, %d\n",
  15663. LocalIsInProxy ? "IN" : "OUT",
  15664. BytesReceivedForAck, WindowForAck);
  15665. #endif
  15666. }
  15667. if (UnlockPointer)
  15668. ChannelPtr->UnlockChannelPointer();
  15669. }
  15670. else
  15671. {
  15672. #if DBG
  15673. DbgPrint("RPCRT4: %d: Channel for User Data %d on connection %p not found\n",
  15674. GetCurrentProcessId(),
  15675. SendContext->UserData,
  15676. this
  15677. );
  15678. #endif
  15679. }
  15680. }
  15681. // successful sends are no-op. Failed sends cause abort. Just
  15682. // turn around the operation status after freeing the packet
  15683. FreeSendContextAndPossiblyData(SendContext);
  15684. // ok to return any error code. See Rule 12
  15685. return EventStatus;
  15686. }
  15687. void HTTP2ProxyVirtualConnection::Abort (
  15688. void
  15689. )
  15690. /*++
  15691. Routine Description:
  15692. Aborts an HTTP connection and disconnects the channels.
  15693. Must only come from neutral context.
  15694. Arguments:
  15695. Return Value:
  15696. --*/
  15697. {
  15698. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_PROXY_VC, 0);
  15699. // abort the channels themselves
  15700. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  15701. // we got to the destructive phase of the abort
  15702. // guard against double aborts
  15703. if (Aborted.Increment() > 1)
  15704. return;
  15705. DisconnectChannels(FALSE, 0);
  15706. }
  15707. void HTTP2ProxyVirtualConnection::DisconnectChannels (
  15708. IN BOOL ExemptChannel,
  15709. IN int ExemptChannelId
  15710. )
  15711. /*++
  15712. Routine Description:
  15713. Disconnects all channels. Must be called from runtime
  15714. or neutral context. Cannot be called from upcall or
  15715. submit context unless an exempt channel is given
  15716. Note that call must synchronize to ensure we're the only
  15717. thread doing the disconnect
  15718. Arguments:
  15719. ExemptChannel - non-zero if ExemptChannelId contains a
  15720. valid exempt channel id. FALSE otherwise.
  15721. ExemptChannelId - if ExemptChannel is non-zero, this argument
  15722. is the id of a channel that will be disconnected, but not
  15723. synchronized with up calls.
  15724. If ExampleChannel is FALSE, this argument is undefined
  15725. Return Value:
  15726. --*/
  15727. {
  15728. while (RundownBlock.GetInteger() > 0)
  15729. {
  15730. Sleep(2);
  15731. }
  15732. RemoveConnectionFromCookieCollection();
  15733. HTTP2VirtualConnection::DisconnectChannels(ExemptChannel,
  15734. ExemptChannelId
  15735. );
  15736. // cancel the timeouts after we have disconnected the channels.
  15737. // Since all timeouts are setup within upcalls
  15738. CancelAllTimeouts();
  15739. }
  15740. RPC_STATUS HTTP2ProxyVirtualConnection::AddConnectionToCookieCollection (
  15741. void
  15742. )
  15743. /*++
  15744. Routine Description:
  15745. Adds this virtual connection to the cookie collection
  15746. Arguments:
  15747. Return Value:
  15748. --*/
  15749. {
  15750. CookieCollection *ProxyCookieCollection;
  15751. HTTP2VirtualConnection *ExistingConnection;
  15752. if (IsInProxy())
  15753. ProxyCookieCollection = GetInProxyCookieCollection();
  15754. else
  15755. ProxyCookieCollection = GetOutProxyCookieCollection();
  15756. ProxyConnectionCookie = new HTTP2ServerCookie(EmbeddedConnectionCookie);
  15757. if (ProxyConnectionCookie == NULL)
  15758. return RPC_S_OUT_OF_MEMORY;
  15759. ProxyConnectionCookie->SetConnection(this);
  15760. IsConnectionInCollection = TRUE;
  15761. ProxyCookieCollection->LockCollection();
  15762. ExistingConnection = ProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  15763. if (ExistingConnection == NULL)
  15764. ProxyCookieCollection->AddElement(ProxyConnectionCookie);
  15765. ProxyCookieCollection->UnlockCollection();
  15766. if (ExistingConnection)
  15767. return RPC_S_PROTOCOL_ERROR;
  15768. else
  15769. return RPC_S_OK;
  15770. }
  15771. void HTTP2ProxyVirtualConnection::RemoveConnectionFromCookieCollection (
  15772. void
  15773. )
  15774. /*++
  15775. Routine Description:
  15776. Removes this virtual connection from the cookie collection
  15777. Arguments:
  15778. Return Value:
  15779. Note:
  15780. This function must be called exactly once and is not thread safe.
  15781. --*/
  15782. {
  15783. CookieCollection *ProxyCookieCollection;
  15784. BOOL DeleteProxyConnectionCookie;
  15785. if (IsConnectionInCollection)
  15786. {
  15787. ASSERT(ProxyConnectionCookie);
  15788. DeleteProxyConnectionCookie = FALSE;
  15789. if (IsInProxy())
  15790. ProxyCookieCollection = GetInProxyCookieCollection();
  15791. else
  15792. ProxyCookieCollection = GetOutProxyCookieCollection();
  15793. ProxyCookieCollection->LockCollection();
  15794. if (ProxyConnectionCookie->RemoveRefCount())
  15795. {
  15796. ProxyCookieCollection->RemoveElement(ProxyConnectionCookie);
  15797. DeleteProxyConnectionCookie = TRUE;
  15798. }
  15799. else
  15800. {
  15801. // the only we we can have a non-zero refcount is if the same
  15802. // machine fakes a web farm.
  15803. ASSERT(ActAsSeparateMachinesOnWebFarm);
  15804. }
  15805. ProxyCookieCollection->UnlockCollection();
  15806. if (DeleteProxyConnectionCookie)
  15807. {
  15808. // delete is outside the lock
  15809. delete ProxyConnectionCookie;
  15810. }
  15811. }
  15812. }
  15813. void HTTP2ProxyVirtualConnection::TimeoutExpired (
  15814. IN TimerContext *pTimer
  15815. )
  15816. /*++
  15817. Routine Description:
  15818. A timeout expired before we cancelled the timer. Abort the connection.
  15819. Arguments:
  15820. Return Value:
  15821. --*/
  15822. {
  15823. BOOL Result;
  15824. Result = AbortAndDestroy(FALSE, // IsFromChannel
  15825. 0, // CallingChannelId
  15826. RPC_P_TIMEOUT
  15827. );
  15828. // if somebody is already destroying it, just return
  15829. if (Result == FALSE)
  15830. return;
  15831. // now 'this' is a pointer disconnected from everybody
  15832. // that we can destroy at our leisure
  15833. delete this;
  15834. // Once we mark the timer as expired, we are no longer protected from
  15835. // the virtual connection being freed during the timer callback.
  15836. // We can't touch the virtual connection after this call.
  15837. TimerExpiredNotify(pTimer);
  15838. }
  15839. RPC_STATUS HTTP2ProxyVirtualConnection::ProxyForwardDataTrafficToDefaultChannel (
  15840. IN BOOL IsInChannel,
  15841. IN BYTE *Packet,
  15842. IN ULONG PacketLength,
  15843. IN ULONG ChannelId
  15844. )
  15845. /*++
  15846. Routine Description:
  15847. Forwards the given packet on the given channel. Overloaded
  15848. version for the proxy as we need to do special things for
  15849. the proxy. It can be used for data traffic only. RTS packets
  15850. cannot use this method, as the TrafficType on the outgoing
  15851. packet will be initialized to http2ttData.
  15852. Arguments:
  15853. IsInChannel - if non-zero, forward to default in channel.
  15854. If 0, forward to default out channel
  15855. Packet - the packet to forward. Ownership of the packet
  15856. passes to this function regardless of success or
  15857. failure.
  15858. PacketLength - the length of the packet to forward
  15859. ChannelId - the id of the channel on which we received the
  15860. packet.
  15861. Return Value:
  15862. RPC_S_OK or RPC_S_* error
  15863. --*/
  15864. {
  15865. HTTP2SendContext *SendContext;
  15866. RPC_STATUS RpcStatus;
  15867. SendContext = AllocateAndInitializeContextFromPacket(Packet,
  15868. PacketLength
  15869. );
  15870. if (SendContext == NULL)
  15871. {
  15872. RpcFreeBuffer(Packet);
  15873. RpcStatus = RPC_S_OUT_OF_MEMORY;
  15874. }
  15875. else
  15876. {
  15877. ASSERT(SendContext->Flags == 0);
  15878. SendContext->Flags = SendContextFlagProxySend;
  15879. SendContext->UserData = ConvertChannelIdToSendContextUserData(ChannelId);
  15880. // make sure we can find it after that
  15881. ASSERT(MapSendContextUserDataToChannelPtr(SendContext->UserData) != NULL);
  15882. RpcStatus = SendTrafficOnDefaultChannel(IsInChannel, // IsInChannel
  15883. SendContext
  15884. );
  15885. // this is a proxy channel - it should not recycle
  15886. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  15887. if (RpcStatus != RPC_S_OK)
  15888. {
  15889. FreeSendContextAndPossiblyData(SendContext);
  15890. }
  15891. }
  15892. return RpcStatus;
  15893. }
  15894. /*********************************************************************
  15895. HTTP2InProxyInChannel
  15896. *********************************************************************/
  15897. RPC_STATUS HTTP2InProxyInChannel::ForwardFlowControlAck (
  15898. IN ULONG BytesReceivedForAck,
  15899. IN ULONG WindowForAck
  15900. )
  15901. /*++
  15902. Routine Description:
  15903. Forwards a flow control ack to the client through the server
  15904. Arguments:
  15905. BytesReceivedForAck - the bytes received when the ACK was issued
  15906. WindowForAck - the free window when the ACK was issued.
  15907. Return Value:
  15908. RPC_S_OK or RPC_S_*
  15909. --*/
  15910. {
  15911. return ForwardFlowControlAckOnDefaultChannel(FALSE, // IsInChannel
  15912. fdClient,
  15913. BytesReceivedForAck,
  15914. WindowForAck
  15915. );
  15916. }
  15917. /*********************************************************************
  15918. HTTP2InProxyOutChannel
  15919. *********************************************************************/
  15920. RPC_STATUS HTTP2InProxyOutChannel::LastPacketSentNotification (
  15921. IN HTTP2SendContext *LastSendContext
  15922. )
  15923. /*++
  15924. Routine Description:
  15925. When a lower channel wants to notify the top
  15926. channel that the last packet has been sent,
  15927. they call this function. Must be called from
  15928. an upcall/neutral context. Only flow control
  15929. senders support last packet notifications
  15930. Arguments:
  15931. LastSendContext - the context for the last send
  15932. Return Value:
  15933. The value to return to the bottom channel
  15934. --*/
  15935. {
  15936. // just return ok to caller. When the server aborts the connection,
  15937. // we will abort too.
  15938. return RPC_S_OK;
  15939. }
  15940. RPC_STATUS HTTP2InProxyOutChannel::SetRawConnectionKeepAlive (
  15941. IN ULONG KeepAliveInterval // in milliseconds
  15942. )
  15943. /*++
  15944. Routine Description:
  15945. Sets the raw connection keep alive. On abort connections
  15946. failures are ignored.
  15947. Arguments:
  15948. KeepAliveInterval - keep alive interval in milliseconds
  15949. Return Value:
  15950. The value to return to the bottom channel
  15951. --*/
  15952. {
  15953. RPC_STATUS RpcStatus;
  15954. WS_HTTP2_CONNECTION *RawConnection;
  15955. KEEPALIVE_TIMEOUT KATimeout;
  15956. RpcStatus = BeginSimpleSubmitAsync();
  15957. if (RpcStatus != RPC_S_OK)
  15958. return RPC_S_OK;
  15959. RawConnection = GetRawConnection();
  15960. KATimeout.Milliseconds = KeepAliveInterval;
  15961. // turn off the old interval
  15962. RpcStatus = WS_TurnOnOffKeepAlives(RawConnection,
  15963. FALSE, // TurnOn
  15964. FALSE, // bProtectIO
  15965. tuMilliseconds,
  15966. KATimeout,
  15967. DefaultClientNoResponseKeepAliveInterval
  15968. );
  15969. // turning off should always succeed
  15970. ASSERT(RpcStatus == RPC_S_OK);
  15971. // turn on the new interval
  15972. // start with the keep alives immediately and proceed until the specified interval
  15973. RpcStatus = WS_TurnOnOffKeepAlives(RawConnection,
  15974. TRUE, // TurnOn
  15975. FALSE, // bProtectIO
  15976. tuMilliseconds,
  15977. KATimeout,
  15978. KeepAliveInterval
  15979. );
  15980. FinishSubmitAsync();
  15981. return RpcStatus;
  15982. }
  15983. /*********************************************************************
  15984. HTTP2InProxyVirtualConnection
  15985. *********************************************************************/
  15986. RPC_STATUS HTTP2InProxyVirtualConnection::InitializeProxyFirstLeg (
  15987. IN USHORT *ServerAddress,
  15988. IN USHORT *ServerPort,
  15989. IN void *ConnectionParameter,
  15990. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface,
  15991. void **IISContext
  15992. )
  15993. /*++
  15994. Routine Description:
  15995. Initialize the proxy (first leg - second leg will happen when we
  15996. receive first RTS packet).
  15997. Arguments:
  15998. ServerAddress - unicode pointer string to the server network address.
  15999. ServerPort - unicode pointer string to the server port
  16000. ConnectionParameter - the extension control block in this case
  16001. ProxyCallbackInterface - a callback interface to the proxy to perform
  16002. various proxy specific functions
  16003. IISContext - on output (success only) it must be initialized to
  16004. the bottom IISChannel for the InProxy.
  16005. Return Value:
  16006. RPC_S_OK or other RPC_S_* errors for error
  16007. --*/
  16008. {
  16009. RPC_STATUS RpcStatus;
  16010. HTTP2InProxyInChannel *NewInChannel;
  16011. int InChannelId;
  16012. int ServerAddressLength; // in characters + terminating 0
  16013. // initialize in channel
  16014. RpcStatus = AllocateAndInitializeInChannel(ConnectionParameter,
  16015. &NewInChannel,
  16016. IISContext
  16017. );
  16018. if (RpcStatus != RPC_S_OK)
  16019. return RpcStatus;
  16020. SetFirstInChannel(NewInChannel);
  16021. this->ProxyCallbackInterface = ProxyCallbackInterface;
  16022. this->ConnectionParameter = ConnectionParameter;
  16023. ServerAddressLength = RpcpStringLength(ServerAddress) + 1;
  16024. ServerName = new RPC_CHAR [ServerAddressLength];
  16025. if (ServerName == NULL)
  16026. {
  16027. Abort();
  16028. return RPC_S_OUT_OF_MEMORY;
  16029. }
  16030. RpcpMemoryCopy(ServerName, ServerAddress, ServerAddressLength * 2);
  16031. RpcStatus = EndpointToPortNumber(ServerPort, this->ServerPort);
  16032. if (RpcStatus != RPC_S_OK)
  16033. {
  16034. Abort();
  16035. // fall through with error
  16036. }
  16037. return RpcStatus;
  16038. }
  16039. RPC_STATUS HTTP2InProxyVirtualConnection::StartProxy (
  16040. void
  16041. )
  16042. /*++
  16043. Routine Description:
  16044. Kicks off listening on the proxy
  16045. Arguments:
  16046. Return Value:
  16047. RPC_S_OK or RPC_S_* for error
  16048. --*/
  16049. {
  16050. HTTP2InProxyInChannel *Channel;
  16051. HTTP2ChannelPointer *ChannelPtr;
  16052. RPC_STATUS RpcStatus;
  16053. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svClosed, 1, 0);
  16054. State.State = http2svClosed; // move to closed state expecting the opening RTS packet
  16055. Channel = LockDefaultInChannel(&ChannelPtr);
  16056. ASSERT(Channel != NULL); // we cannot be disconnected now
  16057. RpcStatus = Channel->Receive(http2ttRaw);
  16058. ChannelPtr->UnlockChannelPointer();
  16059. return RpcStatus;
  16060. }
  16061. C_ASSERT(sizeof(SOCKADDR_IN) == MAX_IPv4_ADDRESS_SIZE);
  16062. C_ASSERT(sizeof(SOCKADDR_IN6) == MAX_IPv6_ADDRESS_SIZE);
  16063. RPC_STATUS HTTP2InProxyVirtualConnection::InitializeProxySecondLeg (
  16064. void
  16065. )
  16066. /*++
  16067. Routine Description:
  16068. Initialize the proxy (second leg - first leg has happened when we
  16069. received the HTTP establishment header).
  16070. Arguments:
  16071. Return Value:
  16072. RPC_S_OK or other RPC_S_* errors for error
  16073. --*/
  16074. {
  16075. RPC_STATUS RpcStatus;
  16076. HTTP2InProxyOutChannel *NewOutChannel;
  16077. int OutChannelId;
  16078. int ServerAddressLength; // in characters + terminating 0
  16079. char ClientIpAddress[16];
  16080. ULONG ClientIpAddressSize;
  16081. ADDRINFO DnsHint;
  16082. ADDRINFO *AddrInfo;
  16083. int err;
  16084. // initialize out channel
  16085. RpcStatus = AllocateAndInitializeOutChannel(
  16086. &NewOutChannel
  16087. );
  16088. if (RpcStatus != RPC_S_OK)
  16089. {
  16090. // this will always come from an upcall. Just return failure
  16091. return RpcStatus;
  16092. }
  16093. SetFirstOutChannel(NewOutChannel);
  16094. RpcStatus = ProxyCallbackInterface->GetConnectionTimeoutFn(&IISConnectionTimeout);
  16095. if (RpcStatus != RPC_S_OK)
  16096. {
  16097. // this will always come from an upcall. Just return failure
  16098. return RpcStatus;
  16099. }
  16100. // convert it from seconds to milliseconds
  16101. IISConnectionTimeout *= 1000;
  16102. ClientIpAddressSize = sizeof(ClientIpAddress);
  16103. RpcStatus = ProxyCallbackInterface->GetClientAddressFn(
  16104. ConnectionParameter,
  16105. ClientIpAddress,
  16106. &ClientIpAddressSize
  16107. );
  16108. ASSERT(RpcStatus != ERROR_INSUFFICIENT_BUFFER);
  16109. if (RpcStatus != RPC_S_OK)
  16110. {
  16111. // this will always come from an upcall. Just return failure
  16112. return RpcStatus;
  16113. }
  16114. RpcpMemorySet(&DnsHint, 0, sizeof(ADDRINFO));
  16115. DnsHint.ai_flags = AI_NUMERICHOST;
  16116. DnsHint.ai_family = PF_UNSPEC;
  16117. err = getaddrinfo(ClientIpAddress,
  16118. NULL,
  16119. &DnsHint,
  16120. &AddrInfo);
  16121. // make sure IIS doesn't feed us garbage IP address
  16122. if (err != ERROR_SUCCESS)
  16123. {
  16124. VALIDATE (GetLastError())
  16125. {
  16126. ERROR_OUTOFMEMORY,
  16127. ERROR_NOT_ENOUGH_MEMORY
  16128. } END_VALIDATE;
  16129. // this will always come from an upcall. Just return failure
  16130. return RPC_S_OUT_OF_MEMORY;
  16131. }
  16132. ASSERT(AddrInfo->ai_family == AF_INET);
  16133. ClientAddress.AddressType = catIPv4;
  16134. RpcpCopyIPv4Address((SOCKADDR_IN *)AddrInfo->ai_addr, (SOCKADDR_IN *)&ClientAddress.u);
  16135. freeaddrinfo(AddrInfo);
  16136. return RpcStatus;
  16137. }
  16138. RPC_STATUS HTTP2InProxyVirtualConnection::ReceiveComplete (
  16139. IN RPC_STATUS EventStatus,
  16140. IN BYTE *Buffer,
  16141. IN UINT BufferLength,
  16142. IN int ChannelId
  16143. )
  16144. /*++
  16145. Routine Description:
  16146. Called by lower layers to indicate receive complete
  16147. Arguments:
  16148. EventStatus - RPC_S_OK for success or RPC_S_* for error
  16149. Buffer - buffer received
  16150. BufferLength - length of buffer received
  16151. ChannelId - which channel completed the operation
  16152. Return Value:
  16153. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  16154. be hidden from the runtime.
  16155. RPC_S_OK if the packet was processed successfully.
  16156. RPC_S_* error if there was an error while processing the
  16157. packet.
  16158. --*/
  16159. {
  16160. RPC_STATUS RpcStatus;
  16161. BOOL BufferFreed = FALSE;
  16162. BOOL MutexCleared;
  16163. HTTP2ChannelPointer *ChannelPtr;
  16164. HTTP2ChannelPointer *ChannelPtr2;
  16165. HTTP2InProxyOutChannel *OutChannel;
  16166. HTTP2InProxyInChannel *InChannel;
  16167. HTTP2InProxyInChannel *InChannel2;
  16168. BYTE *CurrentPosition;
  16169. rpcconn_tunnel_settings *RTS;
  16170. CookieCollection *InProxyCookieCollection;
  16171. HTTP2InProxyVirtualConnection *ExistingConnection;
  16172. HTTP2Cookie NewChannelCookie;
  16173. HTTP2SendContext *EmptyRTS;
  16174. int NonDefaultSelector;
  16175. int DefaultSelector;
  16176. HTTP2SendContext *D3_A2Context;
  16177. HTTP2OtherCmdPacketType PacketType;
  16178. int i;
  16179. ULONG BytesReceivedForAck;
  16180. ULONG WindowForAck;
  16181. HTTP2Cookie CookieForChannel;
  16182. ULONG ServerReceiveWindowSize;
  16183. HTTP2SendContext *SendContext;
  16184. ULONG DefaultInChannelId;
  16185. ULONG NewProtocolVersion;
  16186. VerifyValidChannelId(ChannelId);
  16187. if (EventStatus == RPC_S_OK)
  16188. {
  16189. // N.B. All recieve packets are guaranteed to be
  16190. // validated up to the common conn packet size
  16191. if (IsRTSPacket(Buffer))
  16192. {
  16193. // Intermediate versions of .NET Server 2003 and
  16194. // all versions of Windows XPSP1 send D4/A7 without
  16195. // version information (old D4/A7). .NET Server 2003
  16196. // RTM and later send D4/A7 with version information
  16197. // (new D4/A7). Check for new D4/A7 and convert it
  16198. // to D4/A8 if necessary
  16199. if (IsNewD4_A7Packet (Buffer,
  16200. BufferLength,
  16201. fdServer,
  16202. &NewProtocolVersion))
  16203. {
  16204. // We know that the new protocol version cannot
  16205. // be higher than ours because the new guy in D4 (the
  16206. // new out proxy) can only dumb it down.
  16207. CORRUPTION_ASSERT (NewProtocolVersion <= ProtocolVersion);
  16208. if (NewProtocolVersion > ProtocolVersion)
  16209. {
  16210. RpcFreeBuffer(Buffer);
  16211. return RPC_S_PROTOCOL_ERROR;
  16212. }
  16213. ProtocolVersion = NewProtocolVersion;
  16214. ConvertNewD4_A7ToD4_A8 (Buffer,
  16215. (ULONG *)&BufferLength);
  16216. RpcStatus = RPC_P_PACKET_NEEDS_FORWARDING;
  16217. }
  16218. else
  16219. {
  16220. RpcStatus = CheckPacketForForwarding(Buffer,
  16221. BufferLength,
  16222. fdInProxy
  16223. );
  16224. }
  16225. }
  16226. if (IsRTSPacket(Buffer) && (RpcStatus != RPC_P_PACKET_NEEDS_FORWARDING))
  16227. {
  16228. // RTS packet - check what we need to do with it
  16229. if (IsOtherCmdPacket(Buffer, BufferLength))
  16230. {
  16231. if (IsOutChannel(ChannelId))
  16232. {
  16233. // the only other cmd we expect on the out channel in the proxy are
  16234. // flow control acks
  16235. RpcStatus = ParseAndFreeFlowControlAckPacket (Buffer,
  16236. BufferLength,
  16237. &BytesReceivedForAck,
  16238. &WindowForAck,
  16239. &CookieForChannel
  16240. );
  16241. BufferFreed = TRUE;
  16242. if (RpcStatus != RPC_S_OK)
  16243. return RpcStatus;
  16244. // notify the channel
  16245. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16246. OutChannel = (HTTP2InProxyOutChannel *)ChannelPtr->LockChannelPointer();
  16247. if (OutChannel == NULL)
  16248. return RPC_P_CONNECTION_SHUTDOWN;
  16249. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  16250. WindowForAck
  16251. );
  16252. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  16253. ChannelPtr->UnlockChannelPointer();
  16254. if (RpcStatus != RPC_S_OK)
  16255. return RpcStatus;
  16256. // post another receive
  16257. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  16258. http2ttRaw
  16259. );
  16260. if (RpcStatus != RPC_S_OK)
  16261. return RpcStatus;
  16262. return RPC_P_PACKET_CONSUMED;
  16263. }
  16264. RpcStatus = GetOtherCmdPacketType(Buffer,
  16265. BufferLength,
  16266. &PacketType
  16267. );
  16268. if (RpcStatus == RPC_S_OK)
  16269. {
  16270. switch (PacketType)
  16271. {
  16272. case http2ocptKeepAliveChange:
  16273. RpcStatus = ParseAndFreeKeepAliveChangePacket(Buffer,
  16274. BufferLength,
  16275. &CurrentClientKeepAliveInterval
  16276. );
  16277. BufferFreed = TRUE;
  16278. if (RpcStatus == RPC_S_OK)
  16279. {
  16280. if (CurrentClientKeepAliveInterval == 0)
  16281. CurrentClientKeepAliveInterval = DefaultClientKeepAliveInterval;
  16282. // by now the keep alive interval has been set on the connection.
  16283. // Any new channels will be taken care of by the virtual connection
  16284. // We need to go in and effect this change on the existing channels
  16285. for (i = 0; i < 2; i ++)
  16286. {
  16287. OutChannel = (HTTP2InProxyOutChannel *)OutChannels[0].LockChannelPointer();
  16288. if (OutChannel)
  16289. {
  16290. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  16291. OutChannels[0].UnlockChannelPointer();
  16292. if (RpcStatus != RPC_S_OK)
  16293. break;
  16294. }
  16295. }
  16296. }
  16297. if (RpcStatus == RPC_S_OK)
  16298. {
  16299. // post another receive
  16300. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  16301. http2ttRaw
  16302. );
  16303. if (RpcStatus == RPC_S_OK)
  16304. RpcStatus = RPC_P_PACKET_CONSUMED;
  16305. }
  16306. // return the status code - success or error, both get
  16307. // handled below us
  16308. return RpcStatus;
  16309. break;
  16310. default:
  16311. ASSERT(0);
  16312. return RPC_S_INTERNAL_ERROR;
  16313. }
  16314. }
  16315. }
  16316. MutexCleared = FALSE;
  16317. State.Mutex.Request();
  16318. switch (State.State)
  16319. {
  16320. case http2svClosed:
  16321. // for closed states, we must receive
  16322. // stuff only on the default in channel
  16323. ASSERT(IsDefaultInChannel(ChannelId));
  16324. CurrentPosition = ValidateRTSPacketCommon(Buffer,
  16325. BufferLength
  16326. );
  16327. if (CurrentPosition == NULL)
  16328. {
  16329. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16330. break;
  16331. }
  16332. RTS = (rpcconn_tunnel_settings *)Buffer;
  16333. if ((RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) == 0)
  16334. {
  16335. RpcStatus = ParseAndFreeD1_B1(Buffer,
  16336. BufferLength,
  16337. &ProtocolVersion,
  16338. &EmbeddedConnectionCookie,
  16339. &InChannelCookies[0],
  16340. &ChannelLifetime,
  16341. &AssociationGroupId,
  16342. &CurrentClientKeepAliveInterval
  16343. );
  16344. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  16345. BufferFreed = TRUE;
  16346. if (RpcStatus != RPC_S_OK)
  16347. break;
  16348. if (CurrentClientKeepAliveInterval < MinimumClientKeepAliveInterval)
  16349. {
  16350. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16351. break;
  16352. }
  16353. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svB3W, 1, 0);
  16354. State.State = http2svB3W;
  16355. State.Mutex.Clear();
  16356. MutexCleared = TRUE;
  16357. RpcStatus = InitializeProxySecondLeg();
  16358. if (RpcStatus != RPC_S_OK)
  16359. break;
  16360. RpcStatus = ConnectToServer();
  16361. if (RpcStatus != RPC_S_OK)
  16362. break;
  16363. RpcStatus = SendD1_B2ToServer();
  16364. if (RpcStatus != RPC_S_OK)
  16365. break;
  16366. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  16367. if (RpcStatus != RPC_S_OK)
  16368. break;
  16369. DefaultClientKeepAliveInterval = CurrentClientKeepAliveInterval;
  16370. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16371. if (OutChannel == NULL)
  16372. {
  16373. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16374. break;
  16375. }
  16376. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  16377. ChannelPtr->UnlockChannelPointer();
  16378. // fall through with the error code
  16379. }
  16380. else
  16381. {
  16382. RpcStatus = ParseAndFreeD2_A1 (Buffer,
  16383. BufferLength,
  16384. &ProtocolVersion,
  16385. &EmbeddedConnectionCookie,
  16386. &InChannelCookies[1], // Old cookie - use InChannelCookies[1]
  16387. // as temporary storage only
  16388. &InChannelCookies[0] // New cookie
  16389. );
  16390. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  16391. BufferFreed = TRUE;
  16392. if (RpcStatus != RPC_S_OK)
  16393. break;
  16394. // caller claims this is recycling for an already existing connection
  16395. // find out this connection
  16396. InProxyCookieCollection = GetInProxyCookieCollection();
  16397. InProxyCookieCollection->LockCollection();
  16398. ExistingConnection = (HTTP2InProxyVirtualConnection *)
  16399. InProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  16400. if (ExistingConnection == NULL || ActAsSeparateMachinesOnWebFarm)
  16401. {
  16402. // no dice. Probably we executed on a different machine on the web farm
  16403. // proceed as a standalone connection
  16404. InProxyCookieCollection->UnlockCollection();
  16405. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svB2W, 1, 0);
  16406. State.State = http2svB2W;
  16407. State.Mutex.Clear();
  16408. MutexCleared = TRUE;
  16409. RpcStatus = InitializeProxySecondLeg();
  16410. if (RpcStatus != RPC_S_OK)
  16411. break;
  16412. RpcStatus = ConnectToServer();
  16413. if (RpcStatus != RPC_S_OK)
  16414. break;
  16415. // posts receive on the server channel as
  16416. // well
  16417. RpcStatus = SendD2_A2ToServer();
  16418. if (RpcStatus != RPC_S_OK)
  16419. break;
  16420. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  16421. if (OutChannel == NULL)
  16422. {
  16423. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16424. break;
  16425. }
  16426. RpcStatus = OutChannel->SetRawConnectionKeepAlive(CurrentClientKeepAliveInterval);
  16427. ChannelPtr->UnlockChannelPointer();
  16428. if (RpcStatus != RPC_S_OK)
  16429. break;
  16430. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  16431. }
  16432. else
  16433. {
  16434. // detach the in channel from this connection and attach
  16435. // it to the found connection. Grab a reference to it
  16436. // to prevent the case where it goes away underneath us
  16437. // we know that in its current state the connection is single
  16438. // threaded because we are in the completion path of the
  16439. // only async operation
  16440. RpcStatus = ExistingConnection->SetTimeout(DefaultNoResponseTimeout,
  16441. ExistingConnection->GetInChannelTimer());
  16442. if (RpcStatus != RPC_S_OK)
  16443. break;
  16444. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16445. InChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  16446. // there is no way that somebody detached the channel here
  16447. ASSERT(InChannel);
  16448. // add a reference to keep the channel alive while we disconnect it
  16449. InChannel->AddReference();
  16450. ChannelPtr->UnlockChannelPointer();
  16451. // no need to drain the upcalls - we know we are the only
  16452. // upcall
  16453. ChannelPtr->FreeChannelPointer(
  16454. FALSE, // DrainUpCalls
  16455. FALSE, // CalledFromUpcallContext
  16456. FALSE, // Abort
  16457. RPC_S_OK
  16458. );
  16459. DefaultSelector = ExistingConnection->DefaultInChannelSelector;
  16460. NonDefaultSelector = ExistingConnection->GetNonDefaultInChannelSelector();
  16461. if (ExistingConnection->InChannelCookies[DefaultSelector].Compare (&InChannelCookies[1]))
  16462. {
  16463. // nice try - cookies are different. Ditch the newly established channel
  16464. InProxyCookieCollection->UnlockCollection();
  16465. InChannel->RemoveReference();
  16466. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16467. break;
  16468. }
  16469. InChannel->SetParent(ExistingConnection);
  16470. ExistingConnection->InChannels[NonDefaultSelector].SetChannel(InChannel);
  16471. ExistingConnection->InChannelCookies[NonDefaultSelector].SetCookie(InChannelCookies[0].GetCookie());
  16472. ExistingConnection->InChannelIds[NonDefaultSelector] = ChannelId;
  16473. // check if connection is aborted
  16474. if (ExistingConnection->Aborted.GetInteger() > 0)
  16475. {
  16476. InChannel->Abort(RPC_P_CONNECTION_SHUTDOWN);
  16477. }
  16478. // the extra reference that we added above passes to the existing connection
  16479. // However, below we party on the existing connection and we need to keep it alive
  16480. ExistingConnection->BlockConnectionFromRundown();
  16481. InProxyCookieCollection->UnlockCollection();
  16482. State.Mutex.Clear();
  16483. MutexCleared = TRUE;
  16484. // nuke the rest of the old connection
  16485. // we got to the destructive phase of the abort
  16486. // guard against double aborts
  16487. if (Aborted.Increment() > 1)
  16488. return FALSE;
  16489. // abort the channels
  16490. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  16491. DisconnectChannels(FALSE, // ExemptChannel
  16492. 0 // ExemptChannel id
  16493. );
  16494. delete this;
  16495. // N.B. don't touch the this pointer after here (Duh!)
  16496. ExistingConnection->State.Mutex.Request();
  16497. LogEvent(SU_HTTPv2, EV_STATE, ExistingConnection, IN_CHANNEL_STATE, http2svOpened_A5W, 1, 0);
  16498. ExistingConnection->State.State = http2svOpened_A5W;
  16499. ExistingConnection->State.Mutex.Clear();
  16500. // send D3/A2 to server
  16501. D3_A2Context = AllocateAndInitializeD3_A2(&ExistingConnection->InChannelCookies[NonDefaultSelector]);
  16502. if (D3_A2Context == NULL)
  16503. {
  16504. ExistingConnection->UnblockConnectionFromRundown();
  16505. RpcStatus = RPC_S_OUT_OF_MEMORY;
  16506. break;
  16507. }
  16508. RpcStatus = ExistingConnection->SendTrafficOnDefaultChannel (
  16509. FALSE, // IsInChannel
  16510. D3_A2Context
  16511. );
  16512. if (RpcStatus != RPC_S_OK)
  16513. {
  16514. FreeRTSPacket(D3_A2Context);
  16515. break;
  16516. }
  16517. RpcStatus = ExistingConnection->PostReceiveOnChannel(
  16518. &ExistingConnection->InChannels[NonDefaultSelector],
  16519. http2ttRaw
  16520. );
  16521. ExistingConnection->UnblockConnectionFromRundown();
  16522. // fall through with the obtained RpcStatus
  16523. }
  16524. }
  16525. break;
  16526. case http2svOpened:
  16527. State.Mutex.Clear();
  16528. MutexCleared = TRUE;
  16529. // the only RTS packets we expect in opened state is D2/A5
  16530. RpcStatus = ParseD2_A5 (Buffer,
  16531. BufferLength,
  16532. &NewChannelCookie
  16533. );
  16534. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  16535. {
  16536. RpcFreeBuffer(Buffer);
  16537. break;
  16538. }
  16539. // send D2/A6 immediately, and queue D2/B1 for sending
  16540. // Since D2/A6 is the same as D2/A5 (the packet we just
  16541. // received), we can just forward it
  16542. RpcStatus = ForwardTrafficToDefaultChannel (
  16543. FALSE, // IsInChannel
  16544. Buffer,
  16545. BufferLength
  16546. );
  16547. if (RpcStatus != RPC_S_OK)
  16548. break;
  16549. // we don't own the buffer after a successful send
  16550. BufferFreed = TRUE;
  16551. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  16552. if (OutChannel == NULL)
  16553. {
  16554. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16555. break;
  16556. }
  16557. // Allocate D1/B1
  16558. EmptyRTS = AllocateAndInitializeEmptyRTS ();
  16559. if (EmptyRTS == NULL)
  16560. {
  16561. ChannelPtr->UnlockChannelPointer();
  16562. RpcStatus = RPC_S_OUT_OF_MEMORY;
  16563. break;
  16564. }
  16565. EmptyRTS->Flags = SendContextFlagSendLast;
  16566. RpcStatus = OutChannel->Send(EmptyRTS);
  16567. ChannelPtr->UnlockChannelPointer();
  16568. if (RpcStatus == RPC_S_OK)
  16569. {
  16570. // we're done. There were no queued buffers and D1/B1
  16571. // was sent immediately. When the server aborts its
  16572. // end of the connection, we will close down
  16573. break;
  16574. }
  16575. else if (RpcStatus == ERROR_IO_PENDING)
  16576. {
  16577. // D1/B1 was not sent immediately. When it is sent,
  16578. // the LastPacketSentNotification mechanism will
  16579. // destroy the connection. Return success for know
  16580. RpcStatus = RPC_S_OK;
  16581. }
  16582. else
  16583. {
  16584. // an error occurred during sending. Free the packet and
  16585. // return it back to the caller
  16586. FreeRTSPacket(EmptyRTS);
  16587. }
  16588. break;
  16589. case http2svOpened_A5W:
  16590. // the only RTS packets we expect in opened_A5W state is D3/A5
  16591. RpcStatus = ParseAndFreeD3_A5 (Buffer,
  16592. BufferLength,
  16593. &NewChannelCookie
  16594. );
  16595. BufferFreed = TRUE;
  16596. CancelTimeout(GetInChannelTimer());
  16597. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  16598. break;
  16599. ASSERT(InChannels[0].IsChannelSet() && InChannels[1].IsChannelSet());
  16600. if (InChannelCookies[GetNonDefaultInChannelSelector()].Compare(&NewChannelCookie))
  16601. {
  16602. // abort
  16603. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16604. break;
  16605. }
  16606. // switch channels and get rid of the old channel
  16607. SwitchDefaultInChannelSelector();
  16608. // we received all those packets on the default in channel by
  16609. // definition
  16610. DefaultInChannelId = GetDefaultInChannelId();
  16611. // drain the queue of buffers received on the non-default
  16612. // channel (new channel) and actually send them on the new default channel
  16613. while ((Buffer = (BYTE *) NonDefaultChannelBufferQueue.TakeOffQueue(&BufferLength)) != NULL)
  16614. {
  16615. RpcStatus = ProxyForwardDataTrafficToDefaultChannel (FALSE, // IsInChannel
  16616. Buffer,
  16617. BufferLength,
  16618. DefaultInChannelId
  16619. );
  16620. if (RpcStatus != RPC_S_OK)
  16621. {
  16622. // just exit. During abort the rest of the buffers
  16623. // will be freed
  16624. break;
  16625. }
  16626. }
  16627. // if we finished the loop with an error, bail out
  16628. if (RpcStatus != RPC_S_OK)
  16629. break;
  16630. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  16631. State.State = http2svOpened;
  16632. State.Mutex.Clear();
  16633. MutexCleared = TRUE;
  16634. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16635. InChannel2 = LockDefaultInChannel(&ChannelPtr2);
  16636. if (InChannel2 == NULL)
  16637. {
  16638. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16639. break;
  16640. }
  16641. InChannel = (HTTP2InProxyInChannel *)ChannelPtr->LockChannelPointer();
  16642. if (InChannel == NULL)
  16643. {
  16644. ChannelPtr2->UnlockChannelPointer();
  16645. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16646. break;
  16647. }
  16648. InChannel->TransferReceiveStateToNewChannel(InChannel2);
  16649. ChannelPtr2->UnlockChannelPointer();
  16650. ChannelPtr->UnlockChannelPointer();
  16651. // detach, abort, and release lifetime reference
  16652. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  16653. TRUE, // CalledFromUpcallContext
  16654. TRUE, // Abort
  16655. RPC_P_CONNECTION_SHUTDOWN // AbortStatus
  16656. );
  16657. // return success. When the reference for this receive
  16658. // is removed, the channel will go away
  16659. RpcStatus = RPC_S_OK;
  16660. break;
  16661. case http2svB2W:
  16662. if (IsOutChannel(ChannelId) == FALSE)
  16663. {
  16664. ASSERT(0);
  16665. // make sure client doesn't rush things
  16666. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16667. break;
  16668. }
  16669. RpcStatus = ParseAndFreeD2_B2(Buffer,
  16670. BufferLength,
  16671. &ServerReceiveWindowSize
  16672. );
  16673. BufferFreed = TRUE;
  16674. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  16675. break;
  16676. // we know the connection is legitimate - add ourselves
  16677. // to the collection
  16678. InProxyCookieCollection = GetInProxyCookieCollection();
  16679. InProxyCookieCollection->LockCollection();
  16680. ExistingConnection = (HTTP2InProxyVirtualConnection *)
  16681. InProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  16682. if (ExistingConnection != NULL)
  16683. {
  16684. // the only way we will be in this protocol is if
  16685. // we were faking a web farm
  16686. ASSERT (ActAsSeparateMachinesOnWebFarm);
  16687. ProxyConnectionCookie = ExistingConnection->GetCookie();
  16688. ProxyConnectionCookie->AddRefCount();
  16689. ProxyConnectionCookie->SetConnection(this);
  16690. // remember that we are part of the cookie collection now
  16691. IsConnectionInCollection = TRUE;
  16692. }
  16693. else
  16694. {
  16695. // we truly didn't find anything - add ourselves.
  16696. RpcStatus = AddConnectionToCookieCollection ();
  16697. if (RpcStatus != RPC_S_OK)
  16698. {
  16699. InProxyCookieCollection->UnlockCollection();
  16700. break;
  16701. }
  16702. }
  16703. InProxyCookieCollection->UnlockCollection();
  16704. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  16705. State.State = http2svOpened;
  16706. State.Mutex.Clear();
  16707. MutexCleared = TRUE;
  16708. // unplug the out channel to get the flow going
  16709. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  16710. if (OutChannel == NULL)
  16711. {
  16712. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  16713. break;
  16714. }
  16715. OutChannel->SetPeerReceiveWindow(ServerReceiveWindowSize);
  16716. RpcStatus = OutChannel->Unplug();
  16717. ChannelPtr->UnlockChannelPointer();
  16718. if (RpcStatus != RPC_S_OK)
  16719. break;
  16720. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  16721. http2ttRaw
  16722. );
  16723. break;
  16724. case http2svB3W:
  16725. ASSERT(IsDefaultOutChannel(ChannelId));
  16726. RpcStatus = ParseAndFreeD1_B3(Buffer,
  16727. BufferLength,
  16728. &ServerReceiveWindowSize,
  16729. &ProtocolVersion
  16730. );
  16731. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  16732. BufferFreed = TRUE;
  16733. if (RpcStatus == RPC_S_OK)
  16734. {
  16735. RpcStatus = PostReceiveOnChannel(&OutChannels[0], http2ttRaw);
  16736. if (RpcStatus == RPC_S_OK)
  16737. {
  16738. RpcStatus = AddConnectionToCookieCollection();
  16739. if (RpcStatus == RPC_S_OK)
  16740. {
  16741. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  16742. State.State = http2svOpened;
  16743. State.Mutex.Clear();
  16744. MutexCleared = TRUE;
  16745. OutChannel = (HTTP2InProxyOutChannel *)OutChannels[0].LockChannelPointer();
  16746. if (OutChannel)
  16747. {
  16748. OutChannel->SetPeerReceiveWindow(ServerReceiveWindowSize);
  16749. RpcStatus = OutChannel->Unplug();
  16750. OutChannels[0].UnlockChannelPointer();
  16751. }
  16752. else
  16753. {
  16754. RpcStatus = RPC_P_CONNECTION_CLOSED;
  16755. }
  16756. }
  16757. }
  16758. }
  16759. break;
  16760. default:
  16761. ASSERT(0);
  16762. }
  16763. if (MutexCleared == FALSE)
  16764. State.Mutex.Clear();
  16765. }
  16766. else
  16767. {
  16768. // data packet or RTS packet that needs forwarding. Just forward it
  16769. if (IsDefaultOutChannel(ChannelId))
  16770. {
  16771. // non-RTS packet in any state from out channel
  16772. // is a protocol error
  16773. RpcStatus = RPC_S_PROTOCOL_ERROR;
  16774. }
  16775. else
  16776. {
  16777. if ((State.State == http2svOpened_A5W)
  16778. && (!IsRTSPacket(Buffer)))
  16779. {
  16780. // this thread is racing with a thread that received D3/A5 on the default
  16781. // channel and is trying to switch the default channel and the state. Make
  16782. // the check within the mutex
  16783. State.Mutex.Request();
  16784. if (IsDefaultInChannel(ChannelId) == FALSE)
  16785. {
  16786. // sends on non-default channel in Opened_A5W state get queued until we
  16787. // receive D3/A5
  16788. if (State.State == http2svOpened_A5W)
  16789. {
  16790. if (NonDefaultChannelBufferQueue.PutOnQueue(Buffer, BufferLength))
  16791. {
  16792. State.Mutex.Clear();
  16793. return RPC_S_OUT_OF_MEMORY;
  16794. }
  16795. State.Mutex.Clear();
  16796. // post a receive for the next buffer
  16797. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16798. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  16799. return RPC_S_OK;
  16800. }
  16801. }
  16802. else
  16803. {
  16804. // the channel is default - fall through to forwarding the data
  16805. }
  16806. State.Mutex.Clear();
  16807. }
  16808. RpcStatus = ProxyForwardDataTrafficToDefaultChannel (FALSE, // IsInChannel
  16809. Buffer,
  16810. BufferLength,
  16811. ChannelId
  16812. );
  16813. // ownership of the buffer passed to ProxyForwardDataTrafficToDefaultChannel
  16814. // regardless of success or failure. Make sure we remember that.
  16815. BufferFreed = TRUE;
  16816. if (RpcStatus == RPC_S_OK)
  16817. {
  16818. ChannelPtr = GetChannelPointerFromId(ChannelId);
  16819. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  16820. }
  16821. else
  16822. {
  16823. // fall through with the error
  16824. }
  16825. }
  16826. }
  16827. }
  16828. else
  16829. {
  16830. if (IsInChannel(ChannelId) && !IsDefaultInChannel(ChannelId))
  16831. {
  16832. // ignore errors on non-default in channels. They can go
  16833. // away while we are still sending data to the server.
  16834. // We will destroy the connection when the server is done
  16835. RpcStatus = RPC_S_OK;
  16836. }
  16837. else
  16838. {
  16839. // just turn around the error code
  16840. RpcStatus = EventStatus;
  16841. }
  16842. // in failure cases we don't own the buffer
  16843. BufferFreed = TRUE;
  16844. }
  16845. if (BufferFreed == FALSE)
  16846. RpcFreeBuffer(Buffer);
  16847. return RpcStatus;
  16848. }
  16849. void HTTP2InProxyVirtualConnection::EnableIISSessionClose (
  16850. void
  16851. )
  16852. /*++
  16853. Routine Description:
  16854. Enables close of the IIS session at the IISTransportChannel
  16855. level. Simply delegates to the appropriate channel.
  16856. Arguments:
  16857. Return Value:
  16858. --*/
  16859. {
  16860. // on the in proxy, the in channel has the IISTransport channel
  16861. HTTP2InProxyInChannel *InChannel;
  16862. HTTP2ChannelPointer *ChannelPtr;
  16863. InChannel = LockDefaultInChannel(&ChannelPtr);
  16864. if (InChannel == NULL)
  16865. {
  16866. // somebody aborted the connection - nothing to do
  16867. return;
  16868. }
  16869. InChannel->EnableIISSessionClose();
  16870. ChannelPtr->UnlockChannelPointer();
  16871. }
  16872. void HTTP2InProxyVirtualConnection::DisconnectChannels (
  16873. IN BOOL ExemptChannel,
  16874. IN int ExemptChannelId
  16875. )
  16876. /*++
  16877. Routine Description:
  16878. Disconnects all channels. Must be called from runtime
  16879. or neutral context. Cannot be called from upcall or
  16880. submit context unless an exempt channel is given
  16881. Note that call must synchronize to ensure we're the only
  16882. thread doing the disconnect
  16883. Arguments:
  16884. ExemptChannel - non-zero if ExemptChannelId contains a
  16885. valid exempt channel id. FALSE otherwise.
  16886. ExemptChannelId - if ExemptChannel is non-zero, this argument
  16887. is the id of a channel that will be disconnected, but not
  16888. synchronized with up calls.
  16889. If ExampleChannel is FALSE, this argument is undefined
  16890. Return Value:
  16891. --*/
  16892. {
  16893. BYTE *Buffer;
  16894. UINT BufferLength;
  16895. State.Mutex.Request();
  16896. if (State.State == http2svOpened_A5W)
  16897. {
  16898. while ((Buffer = (BYTE *) NonDefaultChannelBufferQueue.TakeOffQueue(&BufferLength)) != NULL)
  16899. {
  16900. RpcFreeBuffer(Buffer);
  16901. }
  16902. }
  16903. State.Mutex.Clear();
  16904. HTTP2ProxyVirtualConnection::DisconnectChannels(ExemptChannel,
  16905. ExemptChannelId
  16906. );
  16907. }
  16908. RPC_STATUS HTTP2InProxyVirtualConnection::AllocateAndInitializeInChannel (
  16909. IN void *ConnectionParameter,
  16910. OUT HTTP2InProxyInChannel **ReturnInChannel,
  16911. OUT void **IISContext
  16912. )
  16913. /*++
  16914. Routine Description:
  16915. Allocates and initializes the in proxy in channel.
  16916. Arguments:
  16917. ConnectionParameter - really an EXTENSION_CONTROL_BLOCK
  16918. ReturnInChannel - on success the created in channel.
  16919. IISContext - on output, the IISChannel pointer used as
  16920. connection context with IIS.
  16921. Return Value:
  16922. RPC_S_OK or RPC_S_* for error
  16923. --*/
  16924. {
  16925. ULONG MemorySize;
  16926. BYTE *MemoryBlock, *CurrentBlock;
  16927. HTTP2InProxyInChannel *InChannel;
  16928. HTTP2ProxyReceiver *ProxyReceiver;
  16929. HTTP2PingReceiver *PingReceiver;
  16930. HTTP2IISTransportChannel *IISChannel;
  16931. BOOL ProxyReceiverNeedsCleanup;
  16932. BOOL PingReceiverNeedsCleanup;
  16933. BOOL IISChannelNeedsCleanup;
  16934. RPC_STATUS RpcStatus;
  16935. // alocate the in channel
  16936. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyInChannel)
  16937. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver)
  16938. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  16939. + SIZE_OF_OBJECT_AND_PADDING(HTTP2IISTransportChannel);
  16940. MemoryBlock = (BYTE *) new char [MemorySize];
  16941. CurrentBlock = MemoryBlock;
  16942. if (CurrentBlock == NULL)
  16943. return RPC_S_OUT_OF_MEMORY;
  16944. InChannel = (HTTP2InProxyInChannel *) MemoryBlock;
  16945. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyInChannel);
  16946. ProxyReceiver = (HTTP2ProxyReceiver *) CurrentBlock;
  16947. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver);
  16948. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  16949. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  16950. IISChannel = (HTTP2IISTransportChannel *)CurrentBlock;
  16951. // all memory blocks are allocated. Go and initialize them. Use explicit
  16952. // placement
  16953. ProxyReceiverNeedsCleanup = FALSE;
  16954. PingReceiverNeedsCleanup = FALSE;
  16955. IISChannelNeedsCleanup = FALSE;
  16956. RpcStatus = RPC_S_OK;
  16957. IISChannel = new (IISChannel) HTTP2IISTransportChannel (ConnectionParameter);
  16958. IISChannelNeedsCleanup = TRUE;
  16959. ProxyReceiver = new (ProxyReceiver) HTTP2ProxyReceiver (HTTP2InProxyReceiveWindow,
  16960. &RpcStatus);
  16961. if (RpcStatus != RPC_S_OK)
  16962. {
  16963. ProxyReceiver->HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  16964. goto AbortAndExit;
  16965. }
  16966. IISChannel->SetUpperChannel(ProxyReceiver);
  16967. ProxyReceiver->SetLowerChannel(IISChannel);
  16968. ProxyReceiverNeedsCleanup = TRUE;
  16969. PingReceiver = new (PingReceiver) HTTP2PingReceiver(TRUE);
  16970. if (RpcStatus != RPC_S_OK)
  16971. {
  16972. PingReceiver->HTTP2PingReceiver::~HTTP2PingReceiver();
  16973. goto AbortAndExit;
  16974. }
  16975. ProxyReceiver->SetUpperChannel(PingReceiver);
  16976. PingReceiver->SetLowerChannel(ProxyReceiver);
  16977. PingReceiverNeedsCleanup = TRUE;
  16978. InChannel = new (InChannel) HTTP2InProxyInChannel (this, &RpcStatus);
  16979. if (RpcStatus != RPC_S_OK)
  16980. {
  16981. InChannel->HTTP2InProxyInChannel::~HTTP2InProxyInChannel();
  16982. goto AbortAndExit;
  16983. }
  16984. PingReceiver->SetUpperChannel(InChannel);
  16985. InChannel->SetLowerChannel(PingReceiver);
  16986. IISChannel->SetTopChannel(InChannel);
  16987. ProxyReceiver->SetTopChannel(InChannel);
  16988. PingReceiver->SetTopChannel(InChannel);
  16989. ASSERT(RpcStatus == RPC_S_OK);
  16990. *ReturnInChannel = InChannel;
  16991. *IISContext = IISChannel;
  16992. goto CleanupAndExit;
  16993. AbortAndExit:
  16994. if (PingReceiverNeedsCleanup)
  16995. {
  16996. PingReceiver->Abort(RpcStatus);
  16997. PingReceiver->FreeObject();
  16998. }
  16999. else if (ProxyReceiverNeedsCleanup)
  17000. {
  17001. ProxyReceiver->Abort(RpcStatus);
  17002. ProxyReceiver->FreeObject();
  17003. }
  17004. else if (IISChannelNeedsCleanup)
  17005. {
  17006. IISChannel->Abort(RpcStatus);
  17007. IISChannel->FreeObject();
  17008. }
  17009. if (MemoryBlock)
  17010. delete [] MemoryBlock;
  17011. CleanupAndExit:
  17012. return RpcStatus;
  17013. }
  17014. RPC_STATUS HTTP2InProxyVirtualConnection::AllocateAndInitializeOutChannel (
  17015. OUT HTTP2InProxyOutChannel **ReturnOutChannel
  17016. )
  17017. /*++
  17018. Routine Description:
  17019. Allocates and initializes the in proxy out channel.
  17020. Arguments:
  17021. ReturnInChannel - on success the created in channel.
  17022. Return Value:
  17023. RPC_S_OK or RPC_S_* for error
  17024. --*/
  17025. {
  17026. ULONG MemorySize;
  17027. BYTE *MemoryBlock, *CurrentBlock;
  17028. HTTP2InProxyOutChannel *OutChannel;
  17029. HTTP2ProxyPlugChannel *PlugChannel;
  17030. HTTP2FlowControlSender *FlowControlSender;
  17031. HTTP2ProxySocketTransportChannel *RawChannel;
  17032. WS_HTTP2_CONNECTION *RawConnection;
  17033. BOOL PlugChannelNeedsCleanup;
  17034. BOOL FlowControlSenderNeedsCleanup;
  17035. BOOL RawChannelNeedsCleanup;
  17036. BOOL RawConnectionNeedsCleanup;
  17037. RPC_STATUS RpcStatus;
  17038. // alocate the in channel
  17039. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyOutChannel)
  17040. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel)
  17041. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  17042. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel)
  17043. + sizeof(WS_HTTP2_CONNECTION);
  17044. MemoryBlock = (BYTE *) new char [MemorySize];
  17045. CurrentBlock = MemoryBlock;
  17046. if (CurrentBlock == NULL)
  17047. return RPC_S_OUT_OF_MEMORY;
  17048. OutChannel = (HTTP2InProxyOutChannel *) MemoryBlock;
  17049. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2InProxyOutChannel);
  17050. PlugChannel = (HTTP2ProxyPlugChannel *) CurrentBlock;
  17051. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel);
  17052. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  17053. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  17054. RawChannel = (HTTP2ProxySocketTransportChannel *)CurrentBlock;
  17055. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel);
  17056. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  17057. RawConnection->HeaderRead = FALSE;
  17058. RawConnection->ReadHeaderFn = HTTP2ReadHttpLegacyResponse;
  17059. // all memory blocks are allocated. Go and initialize them. Use explicit
  17060. // placement
  17061. PlugChannelNeedsCleanup = FALSE;
  17062. FlowControlSenderNeedsCleanup = FALSE;
  17063. RawChannelNeedsCleanup = FALSE;
  17064. RawConnectionNeedsCleanup = FALSE;
  17065. RawConnection->id = INVALID_PROTOCOL_ID;
  17066. RawConnection->Initialize();
  17067. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  17068. RawConnectionNeedsCleanup = TRUE;
  17069. RpcStatus = RPC_S_OK;
  17070. RawChannel = new (RawChannel) HTTP2ProxySocketTransportChannel (RawConnection, &RpcStatus);
  17071. if (RpcStatus != RPC_S_OK)
  17072. {
  17073. RawChannel->HTTP2ProxySocketTransportChannel::~HTTP2ProxySocketTransportChannel();
  17074. goto AbortAndExit;
  17075. }
  17076. RawConnection->Channel = RawChannel;
  17077. RawChannelNeedsCleanup = TRUE;
  17078. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  17079. FALSE, // SendToRuntime
  17080. &RpcStatus
  17081. );
  17082. if (RpcStatus != RPC_S_OK)
  17083. {
  17084. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  17085. goto AbortAndExit;
  17086. }
  17087. RawChannel->SetUpperChannel(FlowControlSender);
  17088. FlowControlSender->SetLowerChannel(RawChannel);
  17089. FlowControlSenderNeedsCleanup = TRUE;
  17090. PlugChannel = new (PlugChannel) HTTP2ProxyPlugChannel (&RpcStatus);
  17091. if (RpcStatus != RPC_S_OK)
  17092. {
  17093. PlugChannel->HTTP2ProxyPlugChannel::~HTTP2ProxyPlugChannel();
  17094. goto AbortAndExit;
  17095. }
  17096. FlowControlSender->SetUpperChannel(PlugChannel);
  17097. PlugChannel->SetLowerChannel(FlowControlSender);
  17098. PlugChannelNeedsCleanup = TRUE;
  17099. OutChannel = new (OutChannel) HTTP2InProxyOutChannel (this,
  17100. RawConnection,
  17101. &RpcStatus);
  17102. if (RpcStatus != RPC_S_OK)
  17103. {
  17104. OutChannel->HTTP2InProxyOutChannel::~HTTP2InProxyOutChannel();
  17105. goto AbortAndExit;
  17106. }
  17107. PlugChannel->SetUpperChannel(OutChannel);
  17108. OutChannel->SetLowerChannel(PlugChannel);
  17109. RawChannel->SetTopChannel(OutChannel);
  17110. FlowControlSender->SetTopChannel(OutChannel);
  17111. PlugChannel->SetTopChannel(OutChannel);
  17112. ASSERT(RpcStatus == RPC_S_OK);
  17113. *ReturnOutChannel = OutChannel;
  17114. goto CleanupAndExit;
  17115. AbortAndExit:
  17116. RawConnection->fIgnoreFree = TRUE;
  17117. if (PlugChannelNeedsCleanup)
  17118. {
  17119. PlugChannel->Abort(RpcStatus);
  17120. PlugChannel->FreeObject();
  17121. }
  17122. else if (FlowControlSenderNeedsCleanup)
  17123. {
  17124. FlowControlSender->Abort(RpcStatus);
  17125. FlowControlSender->FreeObject();
  17126. }
  17127. else if (RawChannelNeedsCleanup)
  17128. {
  17129. RawChannel->Abort(RpcStatus);
  17130. RawChannel->FreeObject();
  17131. }
  17132. else if (RawConnectionNeedsCleanup)
  17133. {
  17134. RawConnection->RealAbort();
  17135. }
  17136. RawConnection->fIgnoreFree = FALSE;
  17137. if (MemoryBlock)
  17138. delete [] MemoryBlock;
  17139. CleanupAndExit:
  17140. return RpcStatus;
  17141. }
  17142. RPC_STATUS HTTP2InProxyVirtualConnection::ConnectToServer (
  17143. void
  17144. )
  17145. /*++
  17146. Routine Description:
  17147. Connects to the server
  17148. Arguments:
  17149. Return Value:
  17150. RPC_S_OK or RPC_S_* for error
  17151. --*/
  17152. {
  17153. HTTP2ChannelPointer *ChannelPtr;
  17154. HTTP2InProxyOutChannel *OutChannel;
  17155. RPC_STATUS RpcStatus;
  17156. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17157. // we don't have any async operations to abort the connection
  17158. // yet - the out channel must be there
  17159. if (OutChannel == NULL)
  17160. {
  17161. ASSERT(0);
  17162. return RPC_S_INTERNAL_ERROR;
  17163. }
  17164. RpcStatus = OutChannel->InitializeRawConnection(ServerName,
  17165. ServerPort,
  17166. ConnectionTimeout,
  17167. ProxyCallbackInterface->IsValidMachineFn
  17168. );
  17169. ChannelPtr->UnlockChannelPointer();
  17170. return RpcStatus;
  17171. }
  17172. RPC_STATUS HTTP2InProxyVirtualConnection::SendD1_B2ToServer (
  17173. void
  17174. )
  17175. /*++
  17176. Routine Description:
  17177. Sends D1/B2 to server
  17178. Arguments:
  17179. Return Value:
  17180. RPC_S_OK or RPC_S_* for error
  17181. --*/
  17182. {
  17183. HTTP2ChannelPointer *ChannelPtr;
  17184. HTTP2InProxyOutChannel *OutChannel;
  17185. RPC_STATUS RpcStatus;
  17186. HTTP2SendContext *SendContext;
  17187. BOOL SendSucceeded = FALSE;
  17188. SendContext = AllocateAndInitializeD1_B2(ProtocolVersion,
  17189. &EmbeddedConnectionCookie,
  17190. &InChannelCookies[0],
  17191. HTTP2InProxyReceiveWindow,
  17192. IISConnectionTimeout,
  17193. &AssociationGroupId,
  17194. &ClientAddress
  17195. );
  17196. if (SendContext == NULL)
  17197. return RPC_S_OUT_OF_MEMORY;
  17198. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17199. // we don't have any async operations to abort the connection
  17200. // yet - the out channel must be there
  17201. ASSERT(OutChannel);
  17202. RpcStatus = OutChannel->Send(SendContext);
  17203. if (RpcStatus == RPC_S_OK)
  17204. {
  17205. SendSucceeded = TRUE;
  17206. RpcStatus = OutChannel->Receive(http2ttRaw);
  17207. }
  17208. ChannelPtr->UnlockChannelPointer();
  17209. if (SendSucceeded == FALSE)
  17210. {
  17211. FreeRTSPacket(SendContext);
  17212. }
  17213. return RpcStatus;
  17214. }
  17215. RPC_STATUS HTTP2InProxyVirtualConnection::SendD2_A2ToServer (
  17216. void
  17217. )
  17218. /*++
  17219. Routine Description:
  17220. Sends D2/A2 to server
  17221. Arguments:
  17222. Return Value:
  17223. RPC_S_OK or RPC_S_* for error
  17224. --*/
  17225. {
  17226. HTTP2ChannelPointer *ChannelPtr;
  17227. HTTP2InProxyOutChannel *OutChannel;
  17228. RPC_STATUS RpcStatus;
  17229. HTTP2SendContext *SendContext;
  17230. BOOL SendSucceeded = FALSE;
  17231. SendContext = AllocateAndInitializeD2_A2(ProtocolVersion,
  17232. &EmbeddedConnectionCookie,
  17233. &InChannelCookies[1],
  17234. &InChannelCookies[0],
  17235. HTTP2InProxyReceiveWindow,
  17236. IISConnectionTimeout
  17237. );
  17238. if (SendContext == NULL)
  17239. return RPC_S_OUT_OF_MEMORY;
  17240. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17241. // we don't have any async operations to abort the connection
  17242. // yet - the out channel must be there
  17243. ASSERT(OutChannel);
  17244. RpcStatus = OutChannel->Send(SendContext);
  17245. if (RpcStatus == RPC_S_OK)
  17246. {
  17247. SendSucceeded = TRUE;
  17248. RpcStatus = OutChannel->Receive(http2ttRaw);
  17249. }
  17250. ChannelPtr->UnlockChannelPointer();
  17251. if (SendSucceeded == FALSE)
  17252. {
  17253. FreeRTSPacket(SendContext);
  17254. }
  17255. return RpcStatus;
  17256. }
  17257. /*********************************************************************
  17258. HTTP2OutProxyInChannel
  17259. *********************************************************************/
  17260. RPC_STATUS HTTP2OutProxyInChannel::ForwardFlowControlAck (
  17261. IN ULONG BytesReceivedForAck,
  17262. IN ULONG WindowForAck
  17263. )
  17264. /*++
  17265. Routine Description:
  17266. Forwards a flow control ack back to the server
  17267. Arguments:
  17268. BytesReceivedForAck - the bytes received when the ACK was issued
  17269. WindowForAck - the free window when the ACK was issued.
  17270. Return Value:
  17271. RPC_S_OK or RPC_S_*
  17272. --*/
  17273. {
  17274. return ForwardFlowControlAckOnThisChannel(BytesReceivedForAck,
  17275. WindowForAck,
  17276. FALSE // NonChannelData
  17277. );
  17278. }
  17279. /*********************************************************************
  17280. HTTP2OutProxyOutChannel
  17281. *********************************************************************/
  17282. RPC_STATUS HTTP2OutProxyOutChannel::LastPacketSentNotification (
  17283. IN HTTP2SendContext *LastSendContext
  17284. )
  17285. /*++
  17286. Routine Description:
  17287. When a lower channel wants to notify the top
  17288. channel that the last packet has been sent,
  17289. they call this function. Must be called from
  17290. an upcall/neutral context. Only flow control
  17291. senders support last packet notifications
  17292. Arguments:
  17293. LastSendContext - the context for the last send
  17294. Return Value:
  17295. The value to return to the bottom channel
  17296. --*/
  17297. {
  17298. HTTP2OutProxyVirtualConnection *VirtualConnection;
  17299. ASSERT(LastSendContext->Flags & SendContextFlagSendLast);
  17300. ASSERT((LastSendContext->UserData == oplptD4_A10)
  17301. || (LastSendContext->UserData == oplptD5_B3));
  17302. VirtualConnection = (HTTP2OutProxyVirtualConnection *)LockParentPointer();
  17303. // if the connection was already aborted, nothing to do
  17304. if (VirtualConnection == NULL)
  17305. return RPC_P_PACKET_CONSUMED;
  17306. // we know the parent will disconnect from us in their
  17307. // notification
  17308. VirtualConnection->LastPacketSentNotification(ChannelId,
  17309. LastSendContext);
  17310. UnlockParentPointer();
  17311. if (LastSendContext->UserData == oplptD5_B3)
  17312. {
  17313. // if we are about to send D5_B3, this is the last packet
  17314. // on the channel. Detach from the parent and return an
  17315. // error
  17316. DrainUpcallsAndFreeParent();
  17317. }
  17318. // just shutdown the connection or what has remained of it
  17319. // (only this channel in the D5_B3 case)
  17320. return RPC_P_CONNECTION_SHUTDOWN;
  17321. }
  17322. void HTTP2OutProxyOutChannel::PingTrafficSentNotify (
  17323. IN ULONG PingTrafficSize
  17324. )
  17325. /*++
  17326. Routine Description:
  17327. Notifies a channel that ping traffic has been sent.
  17328. Arguments:
  17329. PingTrafficSize - the size of the ping traffic sent.
  17330. --*/
  17331. {
  17332. BOOL Result;
  17333. AccumulatedPingTraffic += PingTrafficSize;
  17334. if (AccumulatedPingTraffic >= AccumulatedPingTrafficNotifyThreshold)
  17335. {
  17336. Result = PingTrafficSentNotifyServer (AccumulatedPingTraffic);
  17337. if (Result)
  17338. AccumulatedPingTraffic = 0;
  17339. }
  17340. }
  17341. BOOL HTTP2OutProxyOutChannel::PingTrafficSentNotifyServer (
  17342. IN ULONG PingTrafficSize
  17343. )
  17344. /*++
  17345. Routine Description:
  17346. Sends a notification to the server that ping traffic originated
  17347. at the out proxy has been sent. This allows to server to do
  17348. proper accounting for when to recycle the out channel.
  17349. Arguments:
  17350. PingTrafficSize - the size of the ping traffic to notify the
  17351. server about.
  17352. Return Value:
  17353. Non-zero if the notification was sent successfully.
  17354. 0 otherwise.
  17355. --*/
  17356. {
  17357. HTTP2OutProxyVirtualConnection *VirtualConnection;
  17358. BOOL Result;
  17359. VirtualConnection = (HTTP2OutProxyVirtualConnection *)LockParentPointer();
  17360. // if the connection was already aborted, nothing to do
  17361. if (VirtualConnection == NULL)
  17362. return TRUE;
  17363. Result = VirtualConnection->PingTrafficSentNotifyServer(PingTrafficSize);
  17364. UnlockParentPointer();
  17365. return Result;
  17366. }
  17367. /*********************************************************************
  17368. HTTP2OutProxyVirtualConnection
  17369. *********************************************************************/
  17370. RPC_STATUS HTTP2OutProxyVirtualConnection::InitializeProxyFirstLeg (
  17371. IN USHORT *ServerAddress,
  17372. IN USHORT *ServerPort,
  17373. IN void *ConnectionParameter,
  17374. IN I_RpcProxyCallbackInterface *ProxyCallbackInterface,
  17375. void **IISContext
  17376. )
  17377. /*++
  17378. Routine Description:
  17379. Initialize the proxy.
  17380. Arguments:
  17381. ServerAddress - unicode pointer string to the server network address.
  17382. ServerPort - unicode pointer string to the server port
  17383. ConnectionParameter - the extension control block in this case
  17384. ProxyCallbackInterface - a callback interface to the proxy to perform
  17385. various proxy specific functions.
  17386. IISContext - on output (success only) it must be initialized to
  17387. the bottom IISChannel for the InProxy.
  17388. Return Value:
  17389. RPC_S_OK or other RPC_S_* errors for error
  17390. --*/
  17391. {
  17392. RPC_STATUS RpcStatus;
  17393. HTTP2OutProxyOutChannel *NewOutChannel;
  17394. int OutChannelId;
  17395. int ServerAddressLength; // in characters + terminating 0
  17396. // initialize out channel
  17397. RpcStatus = AllocateAndInitializeOutChannel(ConnectionParameter,
  17398. &NewOutChannel,
  17399. IISContext
  17400. );
  17401. if (RpcStatus != RPC_S_OK)
  17402. return RpcStatus;
  17403. SetFirstOutChannel(NewOutChannel);
  17404. this->ProxyCallbackInterface = ProxyCallbackInterface;
  17405. this->ConnectionParameter = ConnectionParameter;
  17406. ServerAddressLength = RpcpStringLength(ServerAddress) + 1;
  17407. ServerName = new RPC_CHAR [ServerAddressLength];
  17408. if (ServerName == NULL)
  17409. {
  17410. Abort();
  17411. return RPC_S_OUT_OF_MEMORY;
  17412. }
  17413. RpcpMemoryCopy(ServerName, ServerAddress, ServerAddressLength * 2);
  17414. RpcStatus = EndpointToPortNumber(ServerPort, this->ServerPort);
  17415. if (RpcStatus != RPC_S_OK)
  17416. {
  17417. Abort();
  17418. // fall through with error
  17419. }
  17420. return RpcStatus;
  17421. }
  17422. RPC_STATUS HTTP2OutProxyVirtualConnection::StartProxy (
  17423. void
  17424. )
  17425. /*++
  17426. Routine Description:
  17427. Kicks off listening on the proxy
  17428. Arguments:
  17429. Return Value:
  17430. RPC_S_OK or RPC_S_* for error
  17431. --*/
  17432. {
  17433. HTTP2OutProxyOutChannel *Channel;
  17434. HTTP2ChannelPointer *ChannelPtr;
  17435. RPC_STATUS RpcStatus;
  17436. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svClosed, 1, 0);
  17437. State.State = http2svClosed; // move to closed state expecting the opening RTS packet
  17438. Channel = LockDefaultOutChannel(&ChannelPtr);
  17439. ASSERT(Channel != NULL); // we cannot be disconnected now
  17440. RpcStatus = Channel->Receive(http2ttRaw);
  17441. ChannelPtr->UnlockChannelPointer();
  17442. return RpcStatus;
  17443. }
  17444. RPC_STATUS HTTP2OutProxyVirtualConnection::InitializeProxySecondLeg (
  17445. void
  17446. )
  17447. /*++
  17448. Routine Description:
  17449. Initialize the proxy.
  17450. Arguments:
  17451. Return Value:
  17452. RPC_S_OK or other RPC_S_* errors for error
  17453. --*/
  17454. {
  17455. RPC_STATUS RpcStatus;
  17456. HTTP2OutProxyInChannel *NewInChannel;
  17457. int InChannelId;
  17458. // initialize in channel
  17459. RpcStatus = AllocateAndInitializeInChannel(
  17460. &NewInChannel
  17461. );
  17462. if (RpcStatus != RPC_S_OK)
  17463. {
  17464. // this will always come from an upcall. Just return failure
  17465. return RpcStatus;
  17466. }
  17467. SetFirstInChannel(NewInChannel);
  17468. RpcStatus = ProxyCallbackInterface->GetConnectionTimeoutFn(&IISConnectionTimeout);
  17469. if (RpcStatus != RPC_S_OK)
  17470. {
  17471. // this will always come from an upcall. Just return failure
  17472. return RpcStatus;
  17473. }
  17474. IISConnectionTimeout *= 1000;
  17475. return RpcStatus;
  17476. }
  17477. RPC_STATUS HTTP2OutProxyVirtualConnection::ReceiveComplete (
  17478. IN RPC_STATUS EventStatus,
  17479. IN BYTE *Buffer,
  17480. IN UINT BufferLength,
  17481. IN int ChannelId
  17482. )
  17483. /*++
  17484. Routine Description:
  17485. Called by lower layers to indicate receive complete
  17486. Arguments:
  17487. EventStatus - RPC_S_OK for success or RPC_S_* for error
  17488. Buffer - buffer received
  17489. BufferLength - length of buffer received
  17490. ChannelId - which channel completed the operation
  17491. Return Value:
  17492. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  17493. be hidden from the runtime.
  17494. RPC_S_OK if the packet was processed successfully.
  17495. RPC_S_* error if there was an error while processing the
  17496. packet.
  17497. --*/
  17498. {
  17499. RPC_STATUS RpcStatus;
  17500. BOOL BufferFreed = FALSE;
  17501. BOOL MutexCleared;
  17502. ULONG ChannelLifetime;
  17503. ULONG Ignored;
  17504. HTTP2ChannelPointer *ChannelPtr;
  17505. HTTP2ChannelPointer *ChannelPtr2;
  17506. HTTP2OutProxyOutChannel *OutChannel;
  17507. HTTP2OutProxyOutChannel *OutChannel2;
  17508. CookieCollection *OutProxyCookieCollection;
  17509. BYTE *CurrentPosition;
  17510. rpcconn_tunnel_settings *RTS;
  17511. HTTP2SendContext *D5_A4Context;
  17512. HTTP2OutProxyVirtualConnection *ExistingConnection;
  17513. int NonDefaultSelector;
  17514. int DefaultSelector;
  17515. HTTP2SendContext *D4_A10Context;
  17516. BOOL IsAckOrNak;
  17517. HTTP2SendContext *D5_B3Context;
  17518. ULONG BytesReceivedForAck;
  17519. ULONG WindowForAck;
  17520. HTTP2Cookie CookieForChannel;
  17521. ULONG ClientReceiveWindowSize;
  17522. HTTP2SendContext *SendContext;
  17523. ULONG LocalProtocolVersion;
  17524. VerifyValidChannelId(ChannelId);
  17525. if (EventStatus == RPC_S_OK)
  17526. {
  17527. // N.B. All recieve packets are guaranteed to be
  17528. // validated up to the common conn packet size
  17529. if (IsRTSPacket(Buffer))
  17530. {
  17531. RpcStatus = HTTPTransInfo->CreateThread();
  17532. if (RpcStatus != RPC_S_OK)
  17533. {
  17534. RpcFreeBuffer(Buffer);
  17535. return RpcStatus;
  17536. }
  17537. if (IsD2_A3Packet (Buffer,
  17538. BufferLength,
  17539. &LocalProtocolVersion))
  17540. {
  17541. // the newly acquired version can only be lower than the
  17542. // old version
  17543. CORRUPTION_ASSERT (LocalProtocolVersion <= ProtocolVersion);
  17544. if (LocalProtocolVersion > ProtocolVersion)
  17545. {
  17546. RpcFreeBuffer(Buffer);
  17547. return RPC_S_PROTOCOL_ERROR;
  17548. }
  17549. ProtocolVersion = LocalProtocolVersion;
  17550. RpcStatus = RPC_P_PACKET_NEEDS_FORWARDING;
  17551. }
  17552. else
  17553. {
  17554. RpcStatus = CheckPacketForForwarding(Buffer,
  17555. BufferLength,
  17556. fdOutProxy
  17557. );
  17558. }
  17559. }
  17560. if (IsRTSPacket(Buffer) && (RpcStatus != RPC_P_PACKET_NEEDS_FORWARDING))
  17561. {
  17562. // RTS packet - check what we need to do with it
  17563. if (IsOtherCmdPacket(Buffer, BufferLength))
  17564. {
  17565. // the only other cmd packets we expect in the proxy are
  17566. // flow control acks
  17567. RpcStatus = ParseAndFreeFlowControlAckPacketWithDestination (Buffer,
  17568. BufferLength,
  17569. fdOutProxy,
  17570. &BytesReceivedForAck,
  17571. &WindowForAck,
  17572. &CookieForChannel
  17573. );
  17574. BufferFreed = TRUE;
  17575. if (RpcStatus != RPC_S_OK)
  17576. return RpcStatus;
  17577. // notify the flow control sender about the ack
  17578. OutChannel = (HTTP2OutProxyOutChannel *)MapCookieToAnyChannelPointer(
  17579. &CookieForChannel,
  17580. &ChannelPtr
  17581. );
  17582. if (OutChannel && !IsOutChannel(ChannelPtr))
  17583. {
  17584. CORRUPTION_ASSERT(0);
  17585. ChannelPtr->UnlockChannelPointer();
  17586. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17587. OutChannel = NULL;
  17588. // fall through with the error
  17589. }
  17590. if (OutChannel)
  17591. {
  17592. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  17593. WindowForAck
  17594. );
  17595. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  17596. ChannelPtr->UnlockChannelPointer();
  17597. }
  17598. if (RpcStatus != RPC_S_OK)
  17599. return RpcStatus;
  17600. // post another receive
  17601. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  17602. http2ttRaw
  17603. );
  17604. if (RpcStatus != RPC_S_OK)
  17605. return RpcStatus;
  17606. return RPC_P_PACKET_CONSUMED;
  17607. }
  17608. MutexCleared = FALSE;
  17609. State.Mutex.Request();
  17610. switch (State.State)
  17611. {
  17612. case http2svClosed:
  17613. // for closed states, we must receive
  17614. // stuff only on the default out (client) channel
  17615. ASSERT(IsDefaultOutChannel(ChannelId));
  17616. CurrentPosition = ValidateRTSPacketCommon(Buffer,
  17617. BufferLength
  17618. );
  17619. if (CurrentPosition == NULL)
  17620. {
  17621. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17622. break;
  17623. }
  17624. RTS = (rpcconn_tunnel_settings *)Buffer;
  17625. if ((RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) == 0)
  17626. {
  17627. RpcStatus = ParseAndFreeD1_A1(Buffer,
  17628. BufferLength,
  17629. &ProtocolVersion,
  17630. &EmbeddedConnectionCookie,
  17631. &OutChannelCookies[0],
  17632. &ClientReceiveWindowSize
  17633. );
  17634. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  17635. BufferFreed = TRUE;
  17636. if (RpcStatus == RPC_S_OK)
  17637. {
  17638. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svC1W, 1, 0);
  17639. State.State = http2svC1W;
  17640. State.Mutex.Clear();
  17641. MutexCleared = TRUE;
  17642. RpcStatus = InitializeProxySecondLeg();
  17643. if (RpcStatus != RPC_S_OK)
  17644. break;
  17645. RpcStatus = ConnectToServer();
  17646. if (RpcStatus != RPC_S_OK)
  17647. break;
  17648. RpcStatus = SendHeaderToClient();
  17649. if (RpcStatus != RPC_S_OK)
  17650. break;
  17651. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17652. if (OutChannel == NULL)
  17653. {
  17654. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17655. break;
  17656. }
  17657. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  17658. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  17659. ChannelPtr->UnlockChannelPointer();
  17660. // zero out the in channel cookie
  17661. InChannelCookies[0].ZeroOut();
  17662. if (RpcStatus != RPC_S_OK)
  17663. break;
  17664. RpcStatus = SendD1_A3ToClient();
  17665. if (RpcStatus != RPC_S_OK)
  17666. break;
  17667. RpcStatus = SendD1_A2ToServer(DefaultChannelLifetime);
  17668. }
  17669. }
  17670. else
  17671. {
  17672. RpcStatus = ParseAndFreeD4_A3 (Buffer,
  17673. BufferLength,
  17674. &ProtocolVersion,
  17675. &EmbeddedConnectionCookie,
  17676. &OutChannelCookies[1], // Old cookie - use OutChannelCookies[1]
  17677. // as temporary storage only
  17678. &OutChannelCookies[0], // New cookie
  17679. &ClientReceiveWindowSize
  17680. );
  17681. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  17682. BufferFreed = TRUE;
  17683. if (RpcStatus != RPC_S_OK)
  17684. break;
  17685. // caller claims this is recycling for an already existing connection
  17686. // find out this connection
  17687. OutProxyCookieCollection = GetOutProxyCookieCollection();
  17688. OutProxyCookieCollection->LockCollection();
  17689. ExistingConnection = (HTTP2OutProxyVirtualConnection *)
  17690. OutProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  17691. if (ExistingConnection == NULL || ActAsSeparateMachinesOnWebFarm)
  17692. {
  17693. // no dice. Probably we executed on a different machine on the web farm
  17694. // proceed as a standalone connection
  17695. OutProxyCookieCollection->UnlockCollection();
  17696. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svA11W, 1, 0);
  17697. State.State = http2svA11W;
  17698. State.Mutex.Clear();
  17699. MutexCleared = TRUE;
  17700. RpcStatus = InitializeProxySecondLeg();
  17701. if (RpcStatus != RPC_S_OK)
  17702. break;
  17703. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17704. // we cannot be aborted here
  17705. ASSERT(OutChannel);
  17706. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  17707. // make sure no packets (RTS or other) go out until
  17708. // we get out D4/A11 and send out the header response
  17709. OutChannel->SetStrongPlug();
  17710. ChannelPtr->UnlockChannelPointer();
  17711. // zero out the in channel cookie
  17712. InChannelCookies[0].ZeroOut();
  17713. RpcStatus = ConnectToServer();
  17714. if (RpcStatus != RPC_S_OK)
  17715. break;
  17716. RpcStatus = SendD4_A4ToServer(DefaultChannelLifetime);
  17717. if (RpcStatus != RPC_S_OK)
  17718. break;
  17719. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  17720. http2ttRaw
  17721. );
  17722. }
  17723. else
  17724. {
  17725. // detach the out channel from this connection and attach
  17726. // it to the found connection. Grab a reference to it
  17727. // to prevent the case where it goes away underneath us
  17728. // we know that in its current state the connection is single
  17729. // threaded because we are in the completion path of the
  17730. // only async operation
  17731. ChannelPtr = GetChannelPointerFromId(ChannelId);
  17732. OutChannel = (HTTP2OutProxyOutChannel *)ChannelPtr->LockChannelPointer();
  17733. // there is no way that somebody detached the channel here
  17734. ASSERT(OutChannel);
  17735. // add a reference to keep the channel alive while we disconnect it
  17736. OutChannel->AddReference();
  17737. ChannelPtr->UnlockChannelPointer();
  17738. // no need to drain the upcalls - we know we are the only
  17739. // upcall
  17740. ChannelPtr->FreeChannelPointer(
  17741. FALSE, // DrainUpCalls
  17742. FALSE, // CalledFromUpcallContext
  17743. FALSE, // Abort
  17744. RPC_S_OK
  17745. );
  17746. DefaultSelector = ExistingConnection->DefaultOutChannelSelector;
  17747. NonDefaultSelector = ExistingConnection->GetNonDefaultOutChannelSelector();
  17748. if (ExistingConnection->OutChannelCookies[DefaultSelector].Compare (&OutChannelCookies[1]))
  17749. {
  17750. // nice try - cookies are different. Ditch the newly established channel
  17751. OutProxyCookieCollection->UnlockCollection();
  17752. OutChannel->RemoveReference();
  17753. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17754. break;
  17755. }
  17756. OutChannel2 = ExistingConnection->LockDefaultOutChannel(&ChannelPtr2);
  17757. if (OutChannel2 == NULL)
  17758. {
  17759. OutProxyCookieCollection->UnlockCollection();
  17760. OutChannel->RemoveReference();
  17761. RpcStatus = RPC_S_PROTOCOL_ERROR;
  17762. break;
  17763. }
  17764. ClientReceiveWindowSize = OutChannel2->GetPeerReceiveWindow();
  17765. ChannelPtr2->UnlockChannelPointer();
  17766. OutChannel->SetPeerReceiveWindow(ClientReceiveWindowSize);
  17767. OutChannel->SetParent(ExistingConnection);
  17768. ExistingConnection->OutChannels[NonDefaultSelector].SetChannel(OutChannel);
  17769. ExistingConnection->OutChannelCookies[NonDefaultSelector].SetCookie(OutChannelCookies[0].GetCookie());
  17770. ExistingConnection->OutChannelIds[NonDefaultSelector] = ChannelId;
  17771. // check if connection is aborted
  17772. if (ExistingConnection->Aborted.GetInteger() > 0)
  17773. {
  17774. OutChannel->Abort(RPC_P_CONNECTION_SHUTDOWN);
  17775. }
  17776. // the extra reference that we added above passes to the existing connection
  17777. // However, below we party on the existing connection and we need to keep it alive
  17778. ExistingConnection->BlockConnectionFromRundown();
  17779. OutProxyCookieCollection->UnlockCollection();
  17780. State.Mutex.Clear();
  17781. MutexCleared = TRUE;
  17782. // nuke the rest of the old connection
  17783. // we got to the destructive phase of the abort
  17784. // guard against double aborts
  17785. if (Aborted.Increment() <= 1)
  17786. {
  17787. // abort the channels
  17788. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  17789. DisconnectChannels(FALSE, // ExemptChannel
  17790. 0 // ExemptChannel id
  17791. );
  17792. delete this;
  17793. // N.B. don't touch the this pointer after here
  17794. }
  17795. // post another receive on the new channel
  17796. RpcStatus = PostReceiveOnChannel (&(ExistingConnection->OutChannels[NonDefaultSelector]),
  17797. http2ttRaw);
  17798. if (RpcStatus != RPC_S_OK)
  17799. {
  17800. ExistingConnection->UnblockConnectionFromRundown();
  17801. break;
  17802. }
  17803. ExistingConnection->State.Mutex.Request();
  17804. LogEvent(SU_HTTPv2, EV_STATE, ExistingConnection, OUT_CHANNEL_STATE, http2svOpened_B1W, 1, 0);
  17805. ExistingConnection->State.State = http2svOpened_B1W;
  17806. ExistingConnection->State.Mutex.Clear();
  17807. // send D5/A4 to server
  17808. D5_A4Context = AllocateAndInitializeD5_A4(&ExistingConnection->OutChannelCookies[NonDefaultSelector]);
  17809. if (D5_A4Context == NULL)
  17810. {
  17811. ExistingConnection->UnblockConnectionFromRundown();
  17812. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17813. break;
  17814. }
  17815. RpcStatus = ExistingConnection->SendTrafficOnDefaultChannel (
  17816. TRUE, // IsInChannel
  17817. D5_A4Context
  17818. );
  17819. if (RpcStatus != RPC_S_OK)
  17820. FreeRTSPacket(D5_A4Context);
  17821. ExistingConnection->UnblockConnectionFromRundown();
  17822. // fall through with the obtained RpcStatus
  17823. }
  17824. }
  17825. break;
  17826. case http2svOpened:
  17827. State.Mutex.Clear();
  17828. MutexCleared = TRUE;
  17829. // the only RTS packets we expect in opened state is D4/A9
  17830. RpcStatus = ParseAndFreeD4_A9 (Buffer,
  17831. BufferLength
  17832. );
  17833. BufferFreed = TRUE;
  17834. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  17835. break;
  17836. // queue D4/A10 for sending
  17837. // First, allocate D4/A10
  17838. D4_A10Context = AllocateAndInitializeD4_A10 ();
  17839. if (D4_A10Context == NULL)
  17840. {
  17841. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17842. break;
  17843. }
  17844. D4_A10Context->Flags = SendContextFlagSendLast;
  17845. D4_A10Context->UserData = oplptD4_A10;
  17846. RpcStatus = SendTrafficOnDefaultChannel (FALSE, // IsInChannel
  17847. D4_A10Context);
  17848. if (RpcStatus == RPC_S_OK)
  17849. {
  17850. // we're done. There were no queued buffers and D4/A10
  17851. // was sent immediately. Close down
  17852. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17853. break;
  17854. }
  17855. else if (RpcStatus == ERROR_IO_PENDING)
  17856. {
  17857. // D4/A10 was not sent immediately. When it is sent,
  17858. // the LastPacketSentNotification mechanism will
  17859. // destroy the connection. Return success for know
  17860. RpcStatus = RPC_S_OK;
  17861. }
  17862. else
  17863. {
  17864. // an error occurred during sending. Free the packet and
  17865. // return error back to the caller
  17866. FreeRTSPacket(D4_A10Context);
  17867. }
  17868. // on success, post another receive so that we can get flow control
  17869. // acks and we can keep sending to the client in case there was
  17870. // a queue on the out channel
  17871. if (RpcStatus == RPC_S_OK)
  17872. {
  17873. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  17874. // fall through with any errors
  17875. }
  17876. break;
  17877. case http2svC1W:
  17878. ASSERT(IsDefaultInChannel(ChannelId));
  17879. RpcStatus = ParseD1_C1(Buffer,
  17880. BufferLength,
  17881. &ProtocolVersion,
  17882. &Ignored, // InProxyReceiveWindowSize
  17883. &Ignored // InProxyConnectionTimeout
  17884. );
  17885. if (RpcStatus == RPC_S_OK)
  17886. {
  17887. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  17888. RpcStatus = AddConnectionToCookieCollection();
  17889. if (RpcStatus == RPC_S_OK)
  17890. {
  17891. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  17892. State.State = http2svOpened;
  17893. State.Mutex.Clear();
  17894. MutexCleared = TRUE;
  17895. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17896. if (OutChannel != NULL)
  17897. {
  17898. RpcStatus = OutChannel->ForwardTraffic(Buffer,
  17899. BufferLength
  17900. );
  17901. if (RpcStatus == RPC_S_OK)
  17902. {
  17903. BufferFreed = TRUE;
  17904. RpcStatus = PostReceiveOnChannel(&InChannels[0], http2ttRaw);
  17905. if (RpcStatus == RPC_S_OK)
  17906. {
  17907. RpcStatus = OutChannel->Unplug();
  17908. }
  17909. }
  17910. ChannelPtr->UnlockChannelPointer();
  17911. }
  17912. else
  17913. RpcStatus = RPC_P_CONNECTION_CLOSED;
  17914. }
  17915. }
  17916. break;
  17917. case http2svOpened_CliW:
  17918. break;
  17919. case http2svOpened_B1W:
  17920. State.Mutex.Clear();
  17921. MutexCleared = TRUE;
  17922. // the only RTS packets we expect in opened state is D5/B1 or D2/B2
  17923. RpcStatus = ParseAndFreeD5_B1orB2 (Buffer,
  17924. BufferLength,
  17925. &IsAckOrNak
  17926. );
  17927. BufferFreed = TRUE;
  17928. if (RpcStatus != RPC_S_OK)
  17929. break;
  17930. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  17931. if (OutChannel == NULL)
  17932. {
  17933. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  17934. break;
  17935. }
  17936. // keep an extra reference for after we detach the
  17937. // channel
  17938. OutChannel->AddReference();
  17939. ChannelPtr->UnlockChannelPointer();
  17940. if (IsAckOrNak == FALSE)
  17941. {
  17942. // Nak - nuke the non-default channel
  17943. // and move to state opened
  17944. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  17945. FALSE, // CalledFromUpcallContext
  17946. TRUE, // Abort
  17947. RPC_S_PROTOCOL_ERROR
  17948. );
  17949. // switch to state opened
  17950. State.Mutex.Request();
  17951. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  17952. State.State = http2svOpened;
  17953. State.Mutex.Clear();
  17954. break;
  17955. }
  17956. SwitchDefaultOutChannelSelector();
  17957. // Send D5/B3 to client
  17958. D5_B3Context = AllocateAndInitializeD5_B3();
  17959. if (D5_B3Context == NULL)
  17960. {
  17961. OutChannel->RemoveReference();
  17962. RpcStatus = RPC_S_OUT_OF_MEMORY;
  17963. break;
  17964. }
  17965. D5_B3Context->Flags = SendContextFlagSendLast;
  17966. D5_B3Context->UserData = oplptD5_B3;
  17967. RpcStatus = OutChannel->Send(D5_B3Context);
  17968. if (RpcStatus == RPC_S_OK)
  17969. {
  17970. // synchronous send. Abort and detach the old channel
  17971. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  17972. FALSE, // CalledFromUpcallContext
  17973. TRUE, // Abort
  17974. RPC_P_CONNECTION_SHUTDOWN
  17975. );
  17976. }
  17977. else if (RpcStatus == ERROR_IO_PENDING)
  17978. {
  17979. // async send. Just release our reference
  17980. // and return success
  17981. RpcStatus = RPC_S_OK;
  17982. }
  17983. else
  17984. {
  17985. // failed to send. Abort all
  17986. FreeRTSPacket(D5_B3Context);
  17987. OutChannel->Abort(RpcStatus);
  17988. OutChannel->RemoveReference();
  17989. break;
  17990. }
  17991. // release the extra reference
  17992. OutChannel->RemoveReference();
  17993. // switch to state opened
  17994. State.Mutex.Request();
  17995. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  17996. State.State = http2svOpened;
  17997. State.Mutex.Clear();
  17998. // unplug the newly created channel
  17999. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  18000. if (OutChannel == NULL)
  18001. {
  18002. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  18003. break;
  18004. }
  18005. RpcStatus = OutChannel->Unplug();
  18006. if (RpcStatus != RPC_S_OK)
  18007. {
  18008. ChannelPtr->UnlockChannelPointer();
  18009. break;
  18010. }
  18011. // send the header response to the client
  18012. RpcStatus = SendHeaderToClient();
  18013. if (RpcStatus != RPC_S_OK)
  18014. {
  18015. ChannelPtr->UnlockChannelPointer();
  18016. break;
  18017. }
  18018. // set the connection timeout
  18019. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  18020. ChannelPtr->UnlockChannelPointer();
  18021. if (RpcStatus != RPC_S_OK)
  18022. break;
  18023. // post another receive on the channel
  18024. RpcStatus = PostReceiveOnDefaultChannel(TRUE, // IsInChannel
  18025. http2ttRaw);
  18026. // fall through with the new error code
  18027. break;
  18028. case http2svA11W:
  18029. if (IsOutChannel(ChannelId) == FALSE)
  18030. {
  18031. ASSERT(0);
  18032. // make sure client doesn't rush things
  18033. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18034. break;
  18035. }
  18036. RpcStatus = ParseAndFreeD4_A11(Buffer,
  18037. BufferLength
  18038. );
  18039. BufferFreed = TRUE;
  18040. if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  18041. break;
  18042. // now that we know the new channel is legit, add it to the
  18043. // collection
  18044. OutProxyCookieCollection = GetOutProxyCookieCollection();
  18045. OutProxyCookieCollection->LockCollection();
  18046. ExistingConnection = (HTTP2OutProxyVirtualConnection *)
  18047. OutProxyCookieCollection->FindElement(&EmbeddedConnectionCookie);
  18048. if (ExistingConnection != NULL)
  18049. {
  18050. // the only way we will be in this protocol is if
  18051. // we were faking a web farm
  18052. ASSERT (ActAsSeparateMachinesOnWebFarm);
  18053. ProxyConnectionCookie = ExistingConnection->GetCookie();
  18054. ProxyConnectionCookie->AddRefCount();
  18055. ProxyConnectionCookie->SetConnection(this);
  18056. // remember that we are part of the cookie collection now
  18057. IsConnectionInCollection = TRUE;
  18058. }
  18059. else
  18060. {
  18061. // we truly didn't find anything - add ourselves.
  18062. RpcStatus = AddConnectionToCookieCollection ();
  18063. if (RpcStatus != RPC_S_OK)
  18064. {
  18065. OutProxyCookieCollection->UnlockCollection();
  18066. break;
  18067. }
  18068. }
  18069. OutProxyCookieCollection->UnlockCollection();
  18070. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  18071. State.State = http2svOpened;
  18072. State.Mutex.Clear();
  18073. MutexCleared = TRUE;
  18074. // unplug the out channel to get the flow going
  18075. OutChannel = LockDefaultOutChannel (&ChannelPtr);
  18076. if (OutChannel == NULL)
  18077. {
  18078. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  18079. break;
  18080. }
  18081. RpcStatus = SendHeaderToClient();
  18082. if (RpcStatus != RPC_S_OK)
  18083. {
  18084. ChannelPtr->UnlockChannelPointer();
  18085. break;
  18086. }
  18087. RpcStatus = OutChannel->SetConnectionTimeout(IISConnectionTimeout);
  18088. if (RpcStatus != RPC_S_OK)
  18089. {
  18090. ChannelPtr->UnlockChannelPointer();
  18091. break;
  18092. }
  18093. RpcStatus = OutChannel->Unplug();
  18094. ChannelPtr->UnlockChannelPointer();
  18095. break;
  18096. case http2svOpened_A5W:
  18097. break;
  18098. case http2svB2W:
  18099. break;
  18100. default:
  18101. ASSERT(0);
  18102. }
  18103. if (MutexCleared == FALSE)
  18104. State.Mutex.Clear();
  18105. }
  18106. else
  18107. {
  18108. // data packet or RTS packet that needs forwarding. Just forward it
  18109. ASSERT (IsDefaultInChannel(ChannelId));
  18110. if (State.State == http2svC1W)
  18111. {
  18112. // non-RTS packet or forward RTS packet in C1W state from out channel
  18113. // is a protocol error
  18114. RpcStatus = RPC_S_PROTOCOL_ERROR;
  18115. }
  18116. else
  18117. {
  18118. SendContext = AllocateAndInitializeContextFromPacket(Buffer,
  18119. BufferLength
  18120. );
  18121. // the buffer is converted to send context. We can't free
  18122. // it directly - we must make sure we free it on failure before exit.
  18123. BufferFreed = TRUE;
  18124. if (SendContext == NULL)
  18125. {
  18126. RpcStatus = RPC_S_OUT_OF_MEMORY;
  18127. }
  18128. else
  18129. {
  18130. ASSERT(SendContext->Flags == 0);
  18131. SendContext->Flags = SendContextFlagProxySend;
  18132. SendContext->UserData = ConvertChannelIdToSendContextUserData(ChannelId);
  18133. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  18134. SendContext
  18135. );
  18136. if (RpcStatus == RPC_S_OK)
  18137. {
  18138. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18139. RpcStatus = PostReceiveOnChannel(ChannelPtr, http2ttRaw);
  18140. }
  18141. else
  18142. {
  18143. FreeSendContextAndPossiblyData(SendContext);
  18144. }
  18145. }
  18146. }
  18147. }
  18148. }
  18149. else
  18150. {
  18151. // just turn around the error code
  18152. RpcStatus = EventStatus;
  18153. // in failure cases we don't own the buffer
  18154. BufferFreed = TRUE;
  18155. }
  18156. if (BufferFreed == FALSE)
  18157. RpcFreeBuffer(Buffer);
  18158. return RpcStatus;
  18159. }
  18160. void HTTP2OutProxyVirtualConnection::EnableIISSessionClose (
  18161. void
  18162. )
  18163. /*++
  18164. Routine Description:
  18165. Enables close of the IIS session at the IISTransportChannel
  18166. level. Simply delegates to the appropriate channel.
  18167. Arguments:
  18168. Return Value:
  18169. --*/
  18170. {
  18171. // on the out proxy, the out channel has the IISTransport channel
  18172. HTTP2OutProxyOutChannel *OutChannel;
  18173. HTTP2ChannelPointer *ChannelPtr;
  18174. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  18175. if (OutChannel == NULL)
  18176. {
  18177. // somebody aborted the connection - nothing to do
  18178. return;
  18179. }
  18180. OutChannel->EnableIISSessionClose();
  18181. ChannelPtr->UnlockChannelPointer();
  18182. }
  18183. BOOL HTTP2OutProxyVirtualConnection::PingTrafficSentNotifyServer (
  18184. IN ULONG PingTrafficSize
  18185. )
  18186. /*++
  18187. Routine Description:
  18188. Sends a notification to the server that ping traffic originated
  18189. at the out proxy has been sent. This allows to server to do
  18190. proper accounting for when to recycle the out channel.
  18191. The function is called from neutral upcall context. It can't
  18192. return an error, and it can't abort.
  18193. Arguments:
  18194. PingTrafficSize - the size of the ping traffic to notify the
  18195. server about.
  18196. Return Value:
  18197. Non-zero if the notification was sent successfully.
  18198. 0 otherwise.
  18199. --*/
  18200. {
  18201. HTTP2SendContext *PingTrafficSentContext;
  18202. RPC_STATUS RpcStatus;
  18203. PingTrafficSentContext = AllocateAndInitializePingTrafficSentNotifyPacket (PingTrafficSize);
  18204. if (PingTrafficSentContext == NULL)
  18205. return FALSE;
  18206. RpcStatus = SendTrafficOnDefaultChannel (TRUE, // IsInChannel
  18207. PingTrafficSentContext
  18208. );
  18209. if (RpcStatus != RPC_S_OK)
  18210. {
  18211. FreeRTSPacket(PingTrafficSentContext);
  18212. return FALSE;
  18213. }
  18214. else
  18215. return TRUE;
  18216. }
  18217. RPC_STATUS HTTP2OutProxyVirtualConnection::AllocateAndInitializeInChannel (
  18218. OUT HTTP2OutProxyInChannel **ReturnInChannel
  18219. )
  18220. /*++
  18221. Routine Description:
  18222. Allocates and initializes the out proxy in channel.
  18223. Arguments:
  18224. ReturnInChannel - on success the created in channel.
  18225. Return Value:
  18226. RPC_S_OK or RPC_S_* for error
  18227. --*/
  18228. {
  18229. ULONG MemorySize;
  18230. BYTE *MemoryBlock, *CurrentBlock;
  18231. HTTP2OutProxyInChannel *InChannel;
  18232. HTTP2ProxyReceiver *ProxyReceiver;
  18233. HTTP2ProxySocketTransportChannel *RawChannel;
  18234. WS_HTTP2_CONNECTION *RawConnection;
  18235. BOOL ProxyReceiverNeedsCleanup;
  18236. BOOL RawChannelNeedsCleanup;
  18237. BOOL RawConnectionNeedsCleanup;
  18238. RPC_STATUS RpcStatus;
  18239. // alocate the in channel
  18240. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyInChannel)
  18241. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver)
  18242. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel)
  18243. + sizeof(WS_HTTP2_CONNECTION);
  18244. MemoryBlock = (BYTE *) new char [MemorySize];
  18245. CurrentBlock = MemoryBlock;
  18246. if (CurrentBlock == NULL)
  18247. return RPC_S_OUT_OF_MEMORY;
  18248. InChannel = (HTTP2OutProxyInChannel *) MemoryBlock;
  18249. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyInChannel);
  18250. ProxyReceiver = (HTTP2ProxyReceiver *) CurrentBlock;
  18251. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyReceiver);
  18252. RawChannel = (HTTP2ProxySocketTransportChannel *)CurrentBlock;
  18253. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxySocketTransportChannel);
  18254. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  18255. RawConnection->HeaderRead = FALSE;
  18256. RawConnection->ReadHeaderFn = HTTP2ReadHttpLegacyResponse;
  18257. // all memory blocks are allocated. Go and initialize them. Use explicit
  18258. // placement
  18259. ProxyReceiverNeedsCleanup = FALSE;
  18260. RawChannelNeedsCleanup = FALSE;
  18261. RawConnectionNeedsCleanup = FALSE;
  18262. RawConnection->id = INVALID_PROTOCOL_ID;
  18263. RawConnection->Initialize();
  18264. RawConnection->type = COMPLEX_T | CONNECTION | CLIENT;
  18265. RawConnectionNeedsCleanup = TRUE;
  18266. RpcStatus = RPC_S_OK;
  18267. RawChannel = new (RawChannel) HTTP2ProxySocketTransportChannel (RawConnection, &RpcStatus);
  18268. if (RpcStatus != RPC_S_OK)
  18269. {
  18270. RawChannel->HTTP2ProxySocketTransportChannel::~HTTP2ProxySocketTransportChannel();
  18271. goto AbortAndExit;
  18272. }
  18273. RawConnection->Channel = RawChannel;
  18274. RawChannelNeedsCleanup = TRUE;
  18275. ProxyReceiver = new (ProxyReceiver) HTTP2ProxyReceiver (HTTP2OutProxyReceiveWindow,
  18276. &RpcStatus);
  18277. if (RpcStatus != RPC_S_OK)
  18278. {
  18279. ProxyReceiver->HTTP2ProxyReceiver::~HTTP2ProxyReceiver();
  18280. goto AbortAndExit;
  18281. }
  18282. RawChannel->SetUpperChannel(ProxyReceiver);
  18283. ProxyReceiver->SetLowerChannel(RawChannel);
  18284. ProxyReceiverNeedsCleanup = TRUE;
  18285. InChannel = new (InChannel) HTTP2OutProxyInChannel (this,
  18286. RawConnection,
  18287. &RpcStatus);
  18288. if (RpcStatus != RPC_S_OK)
  18289. {
  18290. InChannel->HTTP2OutProxyInChannel::~HTTP2OutProxyInChannel();
  18291. goto AbortAndExit;
  18292. }
  18293. ProxyReceiver->SetUpperChannel(InChannel);
  18294. InChannel->SetLowerChannel(ProxyReceiver);
  18295. RawChannel->SetTopChannel(InChannel);
  18296. ProxyReceiver->SetTopChannel(InChannel);
  18297. ASSERT(RpcStatus == RPC_S_OK);
  18298. *ReturnInChannel = InChannel;
  18299. goto CleanupAndExit;
  18300. AbortAndExit:
  18301. if (ProxyReceiverNeedsCleanup)
  18302. {
  18303. ProxyReceiver->Abort(RpcStatus);
  18304. ProxyReceiver->FreeObject();
  18305. }
  18306. else if (RawChannelNeedsCleanup)
  18307. {
  18308. RawChannel->Abort(RpcStatus);
  18309. RawChannel->FreeObject();
  18310. }
  18311. else if (RawConnectionNeedsCleanup)
  18312. {
  18313. RawConnection->RealAbort();
  18314. }
  18315. if (MemoryBlock)
  18316. delete [] MemoryBlock;
  18317. CleanupAndExit:
  18318. return RpcStatus;
  18319. }
  18320. RPC_STATUS HTTP2OutProxyVirtualConnection::AllocateAndInitializeOutChannel (
  18321. IN void *ConnectionParameter,
  18322. OUT HTTP2OutProxyOutChannel **ReturnOutChannel,
  18323. OUT void **IISContext
  18324. )
  18325. /*++
  18326. Routine Description:
  18327. Allocates and initializes the out proxy out channel.
  18328. Arguments:
  18329. ConnectionParameter - really an EXTENSION_CONTROL_BLOCK
  18330. ReturnOutChannel - on success the created out channel.
  18331. IISContext - on output, the IISChannel pointer used as
  18332. connection context with IIS.
  18333. Return Value:
  18334. RPC_S_OK or RPC_S_* for error
  18335. --*/
  18336. {
  18337. ULONG MemorySize;
  18338. BYTE *MemoryBlock, *CurrentBlock;
  18339. HTTP2OutProxyOutChannel *OutChannel;
  18340. HTTP2ProxyPlugChannel *PlugChannel;
  18341. HTTP2FlowControlSender *FlowControlSender;
  18342. HTTP2PingOriginator *PingOriginator;
  18343. HTTP2PingReceiver *PingReceiver;
  18344. HTTP2IISSenderTransportChannel *IISChannel;
  18345. BOOL PlugChannelNeedsCleanup;
  18346. BOOL FlowControlSenderNeedsCleanup;
  18347. BOOL PingOriginatorNeedsCleanup;
  18348. BOOL PingReceiverNeedsCleanup;
  18349. BOOL IISChannelNeedsCleanup;
  18350. RPC_STATUS RpcStatus;
  18351. // alocate the in channel
  18352. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyOutChannel)
  18353. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel)
  18354. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  18355. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator)
  18356. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver)
  18357. + SIZE_OF_OBJECT_AND_PADDING(HTTP2IISSenderTransportChannel)
  18358. ;
  18359. MemoryBlock = (BYTE *) new char [MemorySize];
  18360. CurrentBlock = MemoryBlock;
  18361. if (CurrentBlock == NULL)
  18362. return RPC_S_OUT_OF_MEMORY;
  18363. OutChannel = (HTTP2OutProxyOutChannel *) MemoryBlock;
  18364. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2OutProxyOutChannel);
  18365. PlugChannel = (HTTP2ProxyPlugChannel *) CurrentBlock;
  18366. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ProxyPlugChannel);
  18367. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  18368. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  18369. PingOriginator = (HTTP2PingOriginator *)CurrentBlock;
  18370. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingOriginator);
  18371. PingReceiver = (HTTP2PingReceiver *)CurrentBlock;
  18372. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PingReceiver);
  18373. IISChannel = (HTTP2IISSenderTransportChannel *)CurrentBlock;
  18374. // all memory blocks are allocated. Go and initialize them. Use explicit
  18375. // placement
  18376. PlugChannelNeedsCleanup = FALSE;
  18377. FlowControlSenderNeedsCleanup = FALSE;
  18378. PingOriginatorNeedsCleanup = FALSE;
  18379. PingReceiverNeedsCleanup = FALSE;
  18380. IISChannelNeedsCleanup = FALSE;
  18381. RpcStatus = RPC_S_OK;
  18382. IISChannel = new (IISChannel) HTTP2IISSenderTransportChannel (ConnectionParameter, &RpcStatus);
  18383. if (RpcStatus != RPC_S_OK)
  18384. {
  18385. IISChannel->HTTP2IISSenderTransportChannel::~HTTP2IISSenderTransportChannel();
  18386. goto AbortAndExit;
  18387. }
  18388. IISChannelNeedsCleanup = TRUE;
  18389. PingReceiver = new (PingReceiver) HTTP2PingReceiver (FALSE);
  18390. IISChannel->SetUpperChannel(PingReceiver);
  18391. PingReceiver->SetLowerChannel(IISChannel);
  18392. PingReceiverNeedsCleanup = TRUE;
  18393. PingOriginator = new (PingOriginator) HTTP2PingOriginator (
  18394. TRUE // NotifyTopChannelForPings
  18395. );
  18396. PingReceiver->SetUpperChannel(PingOriginator);
  18397. PingOriginator->SetLowerChannel(PingReceiver);
  18398. PingOriginatorNeedsCleanup = TRUE;
  18399. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (FALSE, // IsServer
  18400. FALSE, // SendToRuntime
  18401. &RpcStatus
  18402. );
  18403. if (RpcStatus != RPC_S_OK)
  18404. {
  18405. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  18406. goto AbortAndExit;
  18407. }
  18408. PingOriginator->SetUpperChannel(FlowControlSender);
  18409. FlowControlSender->SetLowerChannel(PingOriginator);
  18410. FlowControlSenderNeedsCleanup = TRUE;
  18411. PlugChannel = new (PlugChannel) HTTP2ProxyPlugChannel (&RpcStatus);
  18412. if (RpcStatus != RPC_S_OK)
  18413. {
  18414. PlugChannel->HTTP2ProxyPlugChannel::~HTTP2ProxyPlugChannel();
  18415. goto AbortAndExit;
  18416. }
  18417. FlowControlSender->SetUpperChannel(PlugChannel);
  18418. PlugChannel->SetLowerChannel(FlowControlSender);
  18419. PlugChannelNeedsCleanup = TRUE;
  18420. OutChannel = new (OutChannel) HTTP2OutProxyOutChannel (this, &RpcStatus);
  18421. if (RpcStatus != RPC_S_OK)
  18422. {
  18423. OutChannel->HTTP2OutProxyOutChannel::~HTTP2OutProxyOutChannel();
  18424. goto AbortAndExit;
  18425. }
  18426. PlugChannel->SetUpperChannel(OutChannel);
  18427. OutChannel->SetLowerChannel(PlugChannel);
  18428. IISChannel->SetTopChannel(OutChannel);
  18429. PingOriginator->SetTopChannel(OutChannel);
  18430. PingReceiver->SetTopChannel(OutChannel);
  18431. FlowControlSender->SetTopChannel(OutChannel);
  18432. PlugChannel->SetTopChannel(OutChannel);
  18433. ASSERT(RpcStatus == RPC_S_OK);
  18434. *ReturnOutChannel = OutChannel;
  18435. *IISContext = IISChannel;
  18436. goto CleanupAndExit;
  18437. AbortAndExit:
  18438. if (PlugChannelNeedsCleanup)
  18439. {
  18440. PlugChannel->Abort(RpcStatus);
  18441. PlugChannel->FreeObject();
  18442. }
  18443. else if (FlowControlSenderNeedsCleanup)
  18444. {
  18445. FlowControlSender->Abort(RpcStatus);
  18446. FlowControlSender->FreeObject();
  18447. }
  18448. else if (PingOriginatorNeedsCleanup)
  18449. {
  18450. PingOriginator->Abort(RpcStatus);
  18451. PingOriginator->FreeObject();
  18452. }
  18453. else if (PingReceiverNeedsCleanup)
  18454. {
  18455. PingReceiver->Abort(RpcStatus);
  18456. PingReceiver->FreeObject();
  18457. }
  18458. else if (IISChannelNeedsCleanup)
  18459. {
  18460. IISChannel->Abort(RpcStatus);
  18461. IISChannel->FreeObject();
  18462. }
  18463. if (MemoryBlock)
  18464. delete [] MemoryBlock;
  18465. CleanupAndExit:
  18466. return RpcStatus;
  18467. }
  18468. RPC_STATUS HTTP2OutProxyVirtualConnection::ConnectToServer (
  18469. void
  18470. )
  18471. /*++
  18472. Routine Description:
  18473. Connects to the server and sends D1/A2
  18474. Arguments:
  18475. Return Value:
  18476. RPC_S_OK or RPC_S_* for error
  18477. --*/
  18478. {
  18479. HTTP2ChannelPointer *ChannelPtr;
  18480. HTTP2OutProxyInChannel *InChannel;
  18481. RPC_STATUS RpcStatus;
  18482. InChannel = LockDefaultInChannel(&ChannelPtr);
  18483. // we cannot be aborted right now
  18484. if (InChannel == NULL)
  18485. {
  18486. ASSERT(0);
  18487. return RPC_S_INTERNAL_ERROR;
  18488. }
  18489. RpcStatus = InChannel->InitializeRawConnection(ServerName,
  18490. ServerPort,
  18491. ConnectionTimeout,
  18492. ProxyCallbackInterface->IsValidMachineFn
  18493. );
  18494. if (RpcStatus == RPC_S_OK)
  18495. {
  18496. RpcStatus = InChannel->Receive(http2ttRaw);
  18497. }
  18498. ChannelPtr->UnlockChannelPointer();
  18499. return RpcStatus;
  18500. }
  18501. RPC_STATUS HTTP2OutProxyVirtualConnection::SendHeaderToClient (
  18502. void
  18503. )
  18504. /*++
  18505. Routine Description:
  18506. Sends response header to client
  18507. Arguments:
  18508. Return Value:
  18509. RPC_S_OK or RPC_S_* for error
  18510. --*/
  18511. {
  18512. RPC_STATUS RpcStatus;
  18513. HTTP2SendContext *SendContext;
  18514. SendContext = AllocateAndInitializeResponseHeader();
  18515. if (SendContext == NULL)
  18516. return RPC_S_OUT_OF_MEMORY;
  18517. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  18518. SendContext
  18519. );
  18520. if (RpcStatus != RPC_S_OK)
  18521. RpcFreeBuffer(SendContext);
  18522. return RpcStatus;
  18523. }
  18524. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD1_A3ToClient (
  18525. void
  18526. )
  18527. /*++
  18528. Routine Description:
  18529. Sends D1/A3 to client
  18530. Arguments:
  18531. Return Value:
  18532. RPC_S_OK or RPC_S_* for error
  18533. --*/
  18534. {
  18535. RPC_STATUS RpcStatus;
  18536. HTTP2SendContext *SendContext;
  18537. SendContext = AllocateAndInitializeD1_A3(IISConnectionTimeout);
  18538. if (SendContext == NULL)
  18539. return RPC_S_OUT_OF_MEMORY;
  18540. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  18541. SendContext
  18542. );
  18543. if (RpcStatus != RPC_S_OK)
  18544. FreeRTSPacket(SendContext);
  18545. return RpcStatus;
  18546. }
  18547. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD1_A2ToServer (
  18548. IN ULONG ChannelLifetime
  18549. )
  18550. /*++
  18551. Routine Description:
  18552. Sends D1/A3 to client
  18553. Arguments:
  18554. ChannelLifetime - the lifetime of the channel as established by
  18555. the client.
  18556. Return Value:
  18557. RPC_S_OK or RPC_S_* for error
  18558. --*/
  18559. {
  18560. RPC_STATUS RpcStatus;
  18561. HTTP2SendContext *SendContext;
  18562. SendContext = AllocateAndInitializeD1_A2 (ProtocolVersion,
  18563. &EmbeddedConnectionCookie,
  18564. &OutChannelCookies[0],
  18565. ChannelLifetime,
  18566. ProxyReceiveWindowSize
  18567. );
  18568. if (SendContext == NULL)
  18569. return RPC_S_OUT_OF_MEMORY;
  18570. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  18571. SendContext
  18572. );
  18573. if (RpcStatus != RPC_S_OK)
  18574. FreeRTSPacket(SendContext);
  18575. return RpcStatus;
  18576. }
  18577. RPC_STATUS HTTP2OutProxyVirtualConnection::SendD4_A4ToServer (
  18578. IN ULONG ChannelLifetime
  18579. )
  18580. /*++
  18581. Routine Description:
  18582. Sends D1/A3 to client
  18583. Arguments:
  18584. ChannelLifetime - the lifetime of the channel as established by
  18585. the client.
  18586. Return Value:
  18587. RPC_S_OK or RPC_S_* for error
  18588. --*/
  18589. {
  18590. RPC_STATUS RpcStatus;
  18591. HTTP2SendContext *SendContext;
  18592. SendContext = AllocateAndInitializeD4_A4 (ProtocolVersion,
  18593. &EmbeddedConnectionCookie,
  18594. &OutChannelCookies[1],
  18595. &OutChannelCookies[0],
  18596. ChannelLifetime,
  18597. ProxyReceiveWindowSize,
  18598. IISConnectionTimeout
  18599. );
  18600. if (SendContext == NULL)
  18601. return RPC_S_OUT_OF_MEMORY;
  18602. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  18603. SendContext
  18604. );
  18605. if (RpcStatus != RPC_S_OK)
  18606. FreeRTSPacket(SendContext);
  18607. return RpcStatus;
  18608. }
  18609. void HTTP2OutProxyVirtualConnection::LastPacketSentNotification (
  18610. IN int ChannelId,
  18611. IN HTTP2SendContext *LastSendContext
  18612. )
  18613. /*++
  18614. Routine Description:
  18615. When a channel wants to notify the virtual connection
  18616. that the last packet has been sent, they call this function.
  18617. Must be called from an upcall/neutral context. Only flow control
  18618. senders generated past packet notifications
  18619. Arguments:
  18620. ChannelId - the channelfor which this notification is.
  18621. LastSendContext - the send context for the last send
  18622. Return Value:
  18623. --*/
  18624. {
  18625. HTTP2ChannelPointer *ChannelPtr;
  18626. ASSERT(LastSendContext->Flags & SendContextFlagSendLast);
  18627. ASSERT((LastSendContext->UserData == oplptD4_A10)
  18628. || (LastSendContext->UserData == oplptD5_B3));
  18629. if (LastSendContext->UserData == oplptD5_B3)
  18630. {
  18631. ChannelPtr = GetChannelPointerFromId(ChannelId);
  18632. if (ChannelPtr == NULL)
  18633. {
  18634. // This should never happen.
  18635. ASSERT(0);
  18636. return;
  18637. }
  18638. // Detach the old channel
  18639. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  18640. TRUE, // CalledFromUpcallContext
  18641. FALSE, // Abort
  18642. RPC_S_OK
  18643. );
  18644. }
  18645. }
  18646. /*********************************************************************
  18647. HTTP2ServerChannel
  18648. *********************************************************************/
  18649. void HTTP2ServerChannel::AbortConnection (
  18650. IN RPC_STATUS AbortReason
  18651. )
  18652. /*++
  18653. Routine Description:
  18654. Aborts the virtual connection.
  18655. Arguments:
  18656. RpcStatus - the error to abort with
  18657. Return Value:
  18658. --*/
  18659. {
  18660. HTTP2VirtualConnection *VirtualConnection;
  18661. // Per Rule 40:
  18662. // We need to syncronize with the channels' being added in InitializeServerConnection().
  18663. // It is possible that another thread is calling SetChannel on the channel pointer
  18664. // and we do not want to ensure mutual exclusion with that thread.
  18665. // The thread in InitializeServerConnection() will be holding CookieCollection mutex.
  18666. // We must take this look before LockParentPointer() to avoid a deadlock with a thread
  18667. // in InitializeServerConnection();
  18668. GetServerCookieCollection()->LockCollection();
  18669. // abort the parent connection
  18670. VirtualConnection = LockParentPointer();
  18671. if (VirtualConnection)
  18672. {
  18673. VirtualConnection->AbortChannels(AbortReason);
  18674. UnlockParentPointer();
  18675. }
  18676. else
  18677. {
  18678. // abort this channel at least
  18679. Abort(AbortReason);
  18680. }
  18681. GetServerCookieCollection()->UnlockCollection();
  18682. }
  18683. /*********************************************************************
  18684. HTTP2ServerInChannel
  18685. *********************************************************************/
  18686. RPC_STATUS HTTP2ServerInChannel::QueryLocalAddress (
  18687. IN OUT void *Buffer,
  18688. IN OUT unsigned long *BufferSize,
  18689. OUT unsigned long *AddressFormat
  18690. )
  18691. /*++
  18692. Routine Description:
  18693. Returns the local IP address of a channel.
  18694. Arguments:
  18695. Buffer - The buffer that will receive the output address
  18696. BufferSize - the size of the supplied Buffer on input. On output the
  18697. number of bytes written to the buffer. If the buffer is too small
  18698. to receive all the output data, ERROR_MORE_DATA is returned,
  18699. nothing is written to the buffer, and BufferSize is set to
  18700. the size of the buffer needed to return all the data.
  18701. AddressFormat - a constant indicating the format of the returned address.
  18702. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  18703. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  18704. Return Value:
  18705. RPC_S_OK or other RPC_S_* errors for error
  18706. --*/
  18707. {
  18708. RPC_STATUS RpcStatus;
  18709. WS_HTTP2_CONNECTION *RawConnection;
  18710. RpcStatus = BeginSimpleSubmitAsync();
  18711. if (RpcStatus != RPC_S_OK)
  18712. return RpcStatus;
  18713. RawConnection = GetRawConnection();
  18714. RpcStatus = TCP_QueryLocalAddress(RawConnection,
  18715. Buffer,
  18716. BufferSize,
  18717. AddressFormat
  18718. );
  18719. FinishSubmitAsync();
  18720. return RpcStatus;
  18721. }
  18722. RPC_STATUS HTTP2ServerInChannel::ForwardFlowControlAck (
  18723. IN ULONG BytesReceivedForAck,
  18724. IN ULONG WindowForAck
  18725. )
  18726. /*++
  18727. Routine Description:
  18728. Forwards a flow control ack back to the in proxy
  18729. Arguments:
  18730. BytesReceivedForAck - the bytes received when the ACK was issued
  18731. WindowForAck - the free window when the ACK was issued.
  18732. Return Value:
  18733. RPC_S_OK or RPC_S_*
  18734. --*/
  18735. {
  18736. RPC_STATUS RpcStatus;
  18737. RpcStatus = ForwardFlowControlAckOnThisChannel(BytesReceivedForAck,
  18738. WindowForAck,
  18739. TRUE // NonChannelData
  18740. );
  18741. // we're sending non-channel data. This cannot lead to channel recycle
  18742. // indication
  18743. ASSERT(RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING);
  18744. return RpcStatus;
  18745. }
  18746. /*********************************************************************
  18747. HTTP2ServerOutChannel
  18748. *********************************************************************/
  18749. RPC_STATUS HTTP2ServerOutChannel::Send (
  18750. IN OUT HTTP2SendContext *SendContext
  18751. )
  18752. /*++
  18753. Routine Description:
  18754. Send request
  18755. Arguments:
  18756. SendContext - the send context
  18757. Return Value:
  18758. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  18759. --*/
  18760. {
  18761. RPC_STATUS RpcStatus;
  18762. BOOL IsDataSend;
  18763. IsDataSend = (SendContext->TrafficType == http2ttData);
  18764. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SERVER_CHANNEL, PtrToUlong(SendContext));
  18765. if (IsDataSend)
  18766. DataSendsPending.Increment();
  18767. RpcStatus = HTTP2ServerChannel::Send(SendContext);
  18768. if (IsDataSend && (RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  18769. DataSendsPending.Decrement();
  18770. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SERVER_CHANNEL, (IsDataSend << 24) | DataSendsPending.GetInteger());
  18771. return RpcStatus;
  18772. }
  18773. RPC_STATUS HTTP2ServerOutChannel::SendComplete (
  18774. IN RPC_STATUS EventStatus,
  18775. IN OUT HTTP2SendContext *SendContext
  18776. )
  18777. /*++
  18778. Routine Description:
  18779. Send complete notification
  18780. Arguments:
  18781. EventStatus - the status of the send
  18782. SendContext - send context
  18783. Return Value:
  18784. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  18785. --*/
  18786. {
  18787. RPC_STATUS RpcStatus;
  18788. BOOL IsDataSend;
  18789. IsDataSend = (SendContext->TrafficType == http2ttData);
  18790. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_SERVER_CHANNEL, PtrToUlong(SendContext));
  18791. if (SendContext->Flags & SendContextFlagAbandonedSend)
  18792. {
  18793. // abandoned send. Complete it silently and return back
  18794. ASSERT(SendContext->TrafficType == http2ttData);
  18795. RpcFreeBuffer(SendContext->u.BufferToFree);
  18796. FreeLastSendContext(SendContext);
  18797. if (IsDataSend)
  18798. DataSendsPending.Decrement();
  18799. ASSERT(DataSendsPending.GetInteger()>=0);
  18800. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_SERVER_CHANNEL, (IsDataSend << 24) | DataSendsPending.GetInteger());
  18801. return RPC_P_PACKET_CONSUMED;
  18802. }
  18803. RpcStatus = HTTP2Channel::SendComplete (EventStatus, SendContext);
  18804. if (IsDataSend)
  18805. DataSendsPending.Decrement();
  18806. ASSERT(DataSendsPending.GetInteger()>=0);
  18807. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_COMPLETE, HTTP2LOG_OT_SERVER_CHANNEL, (IsDataSend << 24) | DataSendsPending.GetInteger());
  18808. return RpcStatus;
  18809. }
  18810. RPC_STATUS HTTP2ServerOutChannel::SyncSend (
  18811. IN HTTP2TrafficType TrafficType,
  18812. IN ULONG BufferLength,
  18813. IN BYTE *Buffer,
  18814. IN BOOL fDisableCancelCheck,
  18815. IN ULONG Timeout,
  18816. IN BASE_ASYNC_OBJECT *Connection,
  18817. IN HTTP2SendContext *SendContext
  18818. )
  18819. /*++
  18820. Routine Description:
  18821. Overwrites HTTP2Channel::SyncSend.
  18822. In the case of HTTP2ServerOutChannel we need to make sure that its
  18823. Send method is called and DataSendsPending counter is incremented.
  18824. Arguments:
  18825. TrafficType - the type of traffic
  18826. BufferLength - the length of the buffer
  18827. Buffer - the buffer to send
  18828. fDisableCancelCheck - don't do checks for cancels. Can be
  18829. used as optimization
  18830. Timeout - the call timeout
  18831. Connection - the transport connection object. Used for cancelling.
  18832. SendContext - a memory block of sufficient size to initialize a send context
  18833. Return Value:
  18834. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  18835. --*/
  18836. {
  18837. RPC_STATUS RpcStatus;
  18838. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SERVER_CHANNEL, 0);
  18839. PrepareForSyncSend (BufferLength,
  18840. Buffer,
  18841. SendContext);
  18842. // In the case of HTTP2ServerOutChannel we need to make sure that its
  18843. // Send method is called and DataSendsPending counter is incremented.
  18844. RpcStatus = Send(SendContext);
  18845. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND, HTTP2LOG_OT_SERVER_CHANNEL, RpcStatus);
  18846. return RpcStatus;
  18847. }
  18848. void HTTP2ServerOutChannel::SendCancelled (
  18849. IN HTTP2SendContext *SendContext
  18850. )
  18851. /*++
  18852. Routine Description:
  18853. A lower channel cancelled a send already passed through this channel.
  18854. Arguments:
  18855. SendContext - the send context of the send that was cancelled
  18856. Return Value:
  18857. --*/
  18858. {
  18859. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_SEND_CANCELLED, HTTP2LOG_OT_SERVER_CHANNEL, PtrToUlong(SendContext));
  18860. HTTP2Channel::SendCancelled(SendContext);
  18861. if(SendContext->TrafficType == http2ttData)
  18862. DataSendsPending.Decrement();
  18863. ASSERT(DataSendsPending.GetInteger()>=0);
  18864. LOG_OPERATION_EXIT(HTTP2LOG_OPERATION_SEND_CANCELLED, HTTP2LOG_OT_SERVER_CHANNEL, DataSendsPending.GetInteger());
  18865. }
  18866. RPC_STATUS HTTP2ServerOutChannel::SetKeepAliveTimeout (
  18867. IN BOOL TurnOn,
  18868. IN BOOL bProtectIO,
  18869. IN KEEPALIVE_TIMEOUT_UNITS Units,
  18870. IN OUT KEEPALIVE_TIMEOUT KATime,
  18871. IN ULONG KAInterval OPTIONAL
  18872. )
  18873. /*++
  18874. Routine Description:
  18875. Change the keep alive value on the channel
  18876. Arguments:
  18877. TurnOn - if non-zero, keep alives are turned on. If zero, keep alives
  18878. are turned off.
  18879. bProtectIO - non-zero if IO needs to be protected against async close
  18880. of the connection.
  18881. Units - in what units is KATime
  18882. KATime - how much to wait before turning on keep alives
  18883. KAInterval - the interval between keep alives
  18884. Return Value:
  18885. RPC_S_OK or other RPC_S_* errors for error
  18886. --*/
  18887. {
  18888. // The server channel does not support this for Whistler
  18889. return RPC_S_CANNOT_SUPPORT;
  18890. }
  18891. RPC_STATUS HTTP2ServerOutChannel::LastPacketSentNotification (
  18892. IN HTTP2SendContext *LastSendContext
  18893. )
  18894. /*++
  18895. Routine Description:
  18896. When a lower channel wants to notify the top
  18897. channel that the last packet has been sent,
  18898. they call this function. Must be called from
  18899. an upcall/neutral context. Only flow control
  18900. senders support past packet notifications
  18901. Arguments:
  18902. LastSendContext - the context for the last send
  18903. Return Value:
  18904. The value to return to the runtime
  18905. --*/
  18906. {
  18907. HTTP2ServerVirtualConnection *VirtualConnection;
  18908. VirtualConnection = LockParentPointer();
  18909. // if the connection was already aborted, nothing to do
  18910. if (VirtualConnection == NULL)
  18911. return RPC_P_PACKET_CONSUMED;
  18912. // we know the parent will disconnect from us in their
  18913. // notification
  18914. VirtualConnection->LastPacketSentNotification(ChannelId,
  18915. LastSendContext);
  18916. UnlockParentPointer();
  18917. DrainUpcallsAndFreeParent();
  18918. return RPC_P_PACKET_CONSUMED;
  18919. }
  18920. RPC_STATUS HTTP2ServerOutChannel::GetChannelOriginatorBufferQueue (
  18921. OUT LIST_ENTRY *NewBufferHead
  18922. )
  18923. /*++
  18924. Routine Description:
  18925. Gets the buffer queue of the channel data originator and if
  18926. any send contexts are done on the cached send context, they are
  18927. moved to an allocated send context.
  18928. Arguments:
  18929. NewBufferHead - the linked list head to add the buffers on.
  18930. The head must be empty.
  18931. Return Value:
  18932. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  18933. --*/
  18934. {
  18935. ASSERT(RpcpIsListEmpty(NewBufferHead));
  18936. GetDataOriginatorChannel()->GetBufferQueue(NewBufferHead);
  18937. return UnaffinitizeSendContextList(NewBufferHead);
  18938. }
  18939. RPC_STATUS HTTP2ServerOutChannel::GetFlowControlSenderBufferQueue (
  18940. OUT LIST_ENTRY *NewBufferHead
  18941. )
  18942. /*++
  18943. Routine Description:
  18944. Gets the buffer queue of the flow control sender channel and if
  18945. any send contexts are done on the cached send context, they are
  18946. moved to an allocated send context.
  18947. Arguments:
  18948. NewBufferHead - the linked list head to add the buffers on.
  18949. The head must be empty.
  18950. Return Value:
  18951. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  18952. --*/
  18953. {
  18954. ASSERT(RpcpIsListEmpty(NewBufferHead));
  18955. GetFlowControlSenderChannel()->GetBufferQueue(NewBufferHead);
  18956. return UnaffinitizeSendContextList(NewBufferHead);
  18957. }
  18958. HTTP2SendContext *HTTP2ServerOutChannel::GetLastSendContext (
  18959. void
  18960. )
  18961. /*++
  18962. Routine Description:
  18963. Gets (creates if necessary) a last send context.
  18964. Arguments:
  18965. Return Value:
  18966. The last context created or NULL if there is not enough memory
  18967. Notes:
  18968. Since each connection will submit one last send at a time, this
  18969. method can be single threaded.
  18970. --*/
  18971. {
  18972. if (CachedLastSendContextUsed == FALSE)
  18973. {
  18974. CachedLastSendContextUsed = TRUE;
  18975. return GetCachedLastSendContext();
  18976. }
  18977. else
  18978. {
  18979. return (new HTTP2SendContext);
  18980. }
  18981. }
  18982. RPC_STATUS HTTP2ServerOutChannel::UnaffinitizeSendContextList (
  18983. IN LIST_ENTRY *ListHead
  18984. )
  18985. /*++
  18986. Routine Description:
  18987. Walks through the supplied list of send contexts and if any
  18988. one is the channel cached context, it allocates a new send
  18989. context and frees the cached context send (i.e. unaffinitizes
  18990. it).
  18991. Arguments:
  18992. ListHead - the list of send contexts. The list may be empty.
  18993. Return Value:
  18994. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  18995. --*/
  18996. {
  18997. LIST_ENTRY *CurrentEntry;
  18998. HTTP2SendContext *CachedSendContext;
  18999. LIST_ENTRY *CachedSendContextListEntry;
  19000. HTTP2SendContext *NewSendContext;
  19001. BOOL CachedSendContextFound;
  19002. LIST_ENTRY *NextListEntry;
  19003. CachedSendContext = GetCachedLastSendContext();
  19004. CachedSendContextListEntry = &CachedSendContext->ListEntry;
  19005. CachedSendContextFound = FALSE;
  19006. CurrentEntry = ListHead->Flink;
  19007. while (CurrentEntry != ListHead)
  19008. {
  19009. if (CurrentEntry == CachedSendContextListEntry)
  19010. {
  19011. ASSERT(CachedLastSendContextUsed);
  19012. // the cached context can be found only once in the list
  19013. ASSERT(CachedSendContextFound == FALSE);
  19014. CachedSendContextFound = TRUE;
  19015. NewSendContext = new HTTP2SendContext;
  19016. if (NewSendContext == NULL)
  19017. {
  19018. // free the whole list and exit
  19019. CurrentEntry = ListHead;
  19020. while (CurrentEntry != ListHead)
  19021. {
  19022. // save the next element before we delete
  19023. NextListEntry = CurrentEntry->Flink;
  19024. FreeLastSendContext(CONTAINING_RECORD(CurrentEntry, HTTP2SendContext, ListEntry));
  19025. // move on to the next
  19026. CurrentEntry = NextListEntry;
  19027. }
  19028. return RPC_S_OUT_OF_MEMORY;
  19029. }
  19030. // copy the context and relink the new entry to the list
  19031. RpcpMemoryCopy(NewSendContext, CachedSendContext, sizeof(HTTP2SendContext));
  19032. NewSendContext->ListEntry.Blink->Flink = &NewSendContext->ListEntry;
  19033. NewSendContext->ListEntry.Flink->Blink = &NewSendContext->ListEntry;
  19034. CurrentEntry = &NewSendContext->ListEntry;
  19035. FreeLastSendContext(CachedSendContext);
  19036. }
  19037. CurrentEntry = CurrentEntry->Flink;
  19038. }
  19039. return RPC_S_OK;
  19040. }
  19041. /*********************************************************************
  19042. HTTP2ServerVirtualConnection
  19043. *********************************************************************/
  19044. void HTTP2ServerVirtualConnection::Abort (
  19045. void
  19046. )
  19047. /*++
  19048. Routine Description:
  19049. Aborts an HTTP connection and disconnects the channels.
  19050. Must only come from the runtime.
  19051. Arguments:
  19052. Return Value:
  19053. --*/
  19054. {
  19055. LOG_OPERATION_ENTRY(HTTP2LOG_OPERATION_ABORT, HTTP2LOG_OT_SERVER_VC, 0);
  19056. // abort the channels themselves
  19057. HTTP2VirtualConnection::AbortChannels(RPC_P_CONNECTION_CLOSED);
  19058. // we got to the destructive phase of the abort
  19059. // guard against double aborts
  19060. if (Aborted.Increment() > 1)
  19061. return;
  19062. // rule 38 - drain the sends before disconnecting
  19063. DrainOutChannelPendingSends ();
  19064. HTTP2VirtualConnection::DisconnectChannels(FALSE, 0);
  19065. CancelAllTimeouts();
  19066. }
  19067. void HTTP2ServerVirtualConnection::Close (
  19068. IN BOOL DontFlush
  19069. )
  19070. /*++
  19071. Routine Description:
  19072. Closes an HTTP connection. Connection may have already been aborted.
  19073. Arguments:
  19074. DontFlush - non-zero if all buffers need to be flushed
  19075. before closing the connection. Zero otherwise.
  19076. Return Value:
  19077. --*/
  19078. {
  19079. CookieCollection *ServerCookieCollection = GetServerCookieCollection();
  19080. ServerCookieCollection->LockCollection();
  19081. ServerCookieCollection->RemoveElement(&EmbeddedConnectionCookie);
  19082. ServerCookieCollection->UnlockCollection();
  19083. HTTP2ServerVirtualConnection::Abort();
  19084. // call destructor without freeing memory
  19085. HTTP2ServerVirtualConnection::~HTTP2ServerVirtualConnection();
  19086. }
  19087. RPC_STATUS HTTP2ServerVirtualConnection::QueryClientAddress (
  19088. OUT RPC_CHAR **pNetworkAddress
  19089. )
  19090. /*++
  19091. Routine Description:
  19092. Returns the IP address of the client on a connection as a string.
  19093. This is a server side function. Assert on the client. Proxies don't
  19094. override that. Other virtual connections may override it.
  19095. Arguments:
  19096. NetworkAddress - Will contain string on success.
  19097. Return Value:
  19098. RPC_S_OK or other RPC_S_* errors for error
  19099. --*/
  19100. {
  19101. ULONG ClientAddressType;
  19102. if (ClientAddress.AddressType == catIPv4)
  19103. {
  19104. ClientAddressType = TCP;
  19105. ((SOCKADDR_IN *)&ClientAddress.u)->sin_family = AF_INET;
  19106. }
  19107. else
  19108. {
  19109. ClientAddressType = TCP_IPv6;
  19110. ((SOCKADDR_IN6 *)&ClientAddress.u)->sin6_family = AF_INET6;
  19111. }
  19112. return WS_ConvertClientAddress((const SOCKADDR *)&ClientAddress.u,
  19113. ClientAddressType,
  19114. pNetworkAddress
  19115. );
  19116. }
  19117. RPC_STATUS HTTP2ServerVirtualConnection::QueryLocalAddress (
  19118. IN OUT void *Buffer,
  19119. IN OUT unsigned long *BufferSize,
  19120. OUT unsigned long *AddressFormat
  19121. )
  19122. /*++
  19123. Routine Description:
  19124. Returns the local IP address of a connection.
  19125. This is a server side function. Assert on the client. Proxies don't
  19126. override that. Other virtual connections may override it.
  19127. Arguments:
  19128. Buffer - The buffer that will receive the output address
  19129. BufferSize - the size of the supplied Buffer on input. On output the
  19130. number of bytes written to the buffer. If the buffer is too small
  19131. to receive all the output data, ERROR_MORE_DATA is returned,
  19132. nothing is written to the buffer, and BufferSize is set to
  19133. the size of the buffer needed to return all the data.
  19134. AddressFormat - a constant indicating the format of the returned address.
  19135. Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
  19136. RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
  19137. Return Value:
  19138. RPC_S_OK or other RPC_S_* errors for error
  19139. --*/
  19140. {
  19141. HTTP2ServerInChannel *ServerInChannel;
  19142. HTTP2ChannelPointer *ChannelPtr;
  19143. RPC_STATUS RpcStatus;
  19144. ServerInChannel = LockDefaultInChannel(&ChannelPtr);
  19145. if (ServerInChannel == NULL)
  19146. return RPC_S_NO_CONTEXT_AVAILABLE;
  19147. RpcStatus = ServerInChannel->QueryLocalAddress(Buffer,
  19148. BufferSize,
  19149. AddressFormat
  19150. );
  19151. ChannelPtr->UnlockChannelPointer();
  19152. return RpcStatus;
  19153. }
  19154. RPC_STATUS HTTP2ServerVirtualConnection::QueryClientId(
  19155. OUT RPC_CLIENT_PROCESS_IDENTIFIER *ClientProcess
  19156. )
  19157. /*++
  19158. Routine Description:
  19159. For secure protocols (which TCP/IP is not) this is supposed to
  19160. give an ID which will be shared by all clients from the same
  19161. process. This prevents one user from grabbing another users
  19162. association group and using their context handles.
  19163. Since TCP/IP is not secure we return the IP address of the
  19164. client machine. This limits the attacks to other processes
  19165. running on the client machine which is better than nothing.
  19166. This is a server side function. Assert on the client. Proxies don't
  19167. override that. Other virtual connections may override it.
  19168. Arguments:
  19169. ClientProcess - Transport identification of the "client".
  19170. Return Value:
  19171. RPC_S_OK or other RPC_S_* errors for error
  19172. --*/
  19173. {
  19174. ClientProcess->SetHTTP2ClientIdentifier(AssociationGroupId.GetCookie(),
  19175. COOKIE_SIZE_IN_BYTES,
  19176. FALSE // fLocal
  19177. );
  19178. return RPC_S_OK;
  19179. }
  19180. RPC_STATUS HTTP2ServerVirtualConnection::QueryClientIpAddress (
  19181. IN OUT RPC_CLIENT_IP_ADDRESS *ClientIpAddress
  19182. )
  19183. /*++
  19184. Routine Description:
  19185. Returns the IP address of the client on a connection.
  19186. This is a server side function. Assert on the client. Proxies don't
  19187. override that. Other virtual connections may override it.
  19188. Arguments:
  19189. ClientIpAddress - Will contain the ip address on success.
  19190. Return Value:
  19191. RPC_S_OK or other RPC_S_* errors for error
  19192. --*/
  19193. {
  19194. ULONG BufferLength = max(sizeof(SOCKADDR_IN), sizeof(SOCKADDR_IN6));
  19195. if (ClientAddress.AddressType == catIPv4)
  19196. {
  19197. ((SOCKADDR_IN *)&ClientAddress.u)->sin_family = AF_INET;
  19198. BufferLength = sizeof(SOCKADDR_IN);
  19199. }
  19200. else
  19201. {
  19202. ((SOCKADDR_IN6 *)&ClientAddress.u)->sin6_family = AF_INET6;
  19203. BufferLength = sizeof(SOCKADDR_IN6);
  19204. }
  19205. ASSERT(BufferLength <= sizeof(*ClientIpAddress));
  19206. ClientIpAddress->DataSize = BufferLength;
  19207. RpcpMemoryCopy (ClientIpAddress, &ClientAddress.u, BufferLength);
  19208. return RPC_S_OK;
  19209. }
  19210. void HTTP2ServerVirtualConnection::LastPacketSentNotification (
  19211. IN int ChannelId,
  19212. IN HTTP2SendContext *LastSendContext
  19213. )
  19214. /*++
  19215. Routine Description:
  19216. When a channel wants to notify the virtual connection
  19217. that the last packet has been sent, they call this function.
  19218. Must be called from an upcall/neutral context. Only flow control
  19219. senders generates last packet notifications
  19220. Arguments:
  19221. ChannelId - the channelfor which this notification is.
  19222. LastSendContext - the context for the last send
  19223. Return Value:
  19224. --*/
  19225. {
  19226. // this must not be on the default in channel
  19227. ASSERT(IsOutChannel(ChannelId));
  19228. ASSERT(!IsDefaultOutChannel(ChannelId));
  19229. // detach the channel that notified us. Since we're in upcall, we know
  19230. // we hold at least one reference
  19231. OutChannels[GetNonDefaultOutChannelSelector()].FreeChannelPointer(FALSE, // DrainUpCalls
  19232. FALSE, // CalledFromUpcallContext
  19233. FALSE, // Abort
  19234. RPC_S_OK // AbortStatus
  19235. );
  19236. }
  19237. RPC_STATUS HTTP2ServerVirtualConnection::RecycleChannel (
  19238. IN BOOL
  19239. )
  19240. /*++
  19241. Routine Description:
  19242. Initiates channel recycling on the server.
  19243. Arguments:
  19244. IsFromUpcall - non-zero if it comes from upcall. Zero otherwise.
  19245. Ignored for server side recycling.
  19246. Return Value:
  19247. RPC_S_OK of the recycling operation started successfully.
  19248. RPC_S_* error for errors.
  19249. --*/
  19250. {
  19251. HTTP2SendContext *D4_A1Context;
  19252. RPC_STATUS RpcStatus;
  19253. #if DBG
  19254. DbgPrint("RPCRT4: %d: Recycling OUT channel\n", GetCurrentProcessId());
  19255. #endif
  19256. InChannelState.Mutex.Request();
  19257. // we shouldn't get recycle unless we're in an opened state
  19258. ASSERT(OutChannelState.State == http2svOpened);
  19259. // we shouldn't recycle the default channel unless the non-default
  19260. // is discarded. If we were to do this, this raises a race condition
  19261. // where a third channel can arrive while the first is still not
  19262. // discarded. To prevent this, we hold the ball until the first
  19263. // channel is discarded, and then we open the flood gates for
  19264. // new channel recycling. See how we handle delayed channel recycling
  19265. // in HTTP2ServerVirtualConnection::ReceiveComplete
  19266. if (OutChannels[GetNonDefaultOutChannelSelector()].IsChannelSet())
  19267. {
  19268. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svNonDefaultChannelCloseWait, 1, 0);
  19269. OutChannelState.State = http2svNonDefaultChannelCloseWait;
  19270. InChannelState.Mutex.Clear();
  19271. return RPC_S_OK;
  19272. }
  19273. // Send invitation to the client to start channel recycling
  19274. D4_A1Context = AllocateAndInitializeD4_A1 ();
  19275. if (D4_A1Context == NULL)
  19276. return RPC_S_OUT_OF_MEMORY;
  19277. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened_A4W, 1, 0);
  19278. OutChannelState.State = http2svOpened_A4W;
  19279. VerifyTimerNotSet (GetOutChannelTimer());
  19280. InChannelState.Mutex.Clear();
  19281. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  19282. D4_A1Context
  19283. );
  19284. if (RpcStatus != RPC_S_OK)
  19285. FreeRTSPacket(D4_A1Context);
  19286. return RpcStatus;
  19287. }
  19288. RPC_STATUS HTTP2ServerVirtualConnection::SendComplete (
  19289. IN RPC_STATUS EventStatus,
  19290. IN OUT HTTP2SendContext *SendContext,
  19291. IN int ChannelId
  19292. )
  19293. /*++
  19294. Routine Description:
  19295. Called by lower layers to indicate send complete.
  19296. Arguments:
  19297. EventStatus - status of the operation
  19298. SendContext - the context for the send complete
  19299. ChannelId - which channel completed the operation
  19300. Return Value:
  19301. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  19302. be hidden from the runtime.
  19303. RPC_S_OK if the packet was processed successfully.
  19304. RPC_S_* error if there was an error while processing the
  19305. packet.
  19306. --*/
  19307. {
  19308. VerifyValidChannelId(ChannelId);
  19309. if (SendContext->TrafficType == http2ttRTS)
  19310. {
  19311. FreeSendContextAndPossiblyData(SendContext);
  19312. if (EventStatus != RPC_S_OK)
  19313. {
  19314. // any send failures on the server are cause for connection abortion
  19315. AbortChannels(EventStatus);
  19316. }
  19317. return RPC_P_PACKET_CONSUMED;
  19318. }
  19319. else
  19320. return EventStatus;
  19321. }
  19322. RPC_STATUS HTTP2ServerVirtualConnection::ReceiveComplete (
  19323. IN RPC_STATUS EventStatus,
  19324. IN BYTE *Buffer,
  19325. IN UINT BufferLength,
  19326. IN int ChannelId
  19327. )
  19328. /*++
  19329. Routine Description:
  19330. Called by lower layers to indicate receive complete
  19331. Arguments:
  19332. EventStatus - RPC_S_OK for success or RPC_S_* for error
  19333. Buffer - buffer received
  19334. BufferLength - length of buffer received
  19335. ChannelId - which channel completed the operation
  19336. Return Value:
  19337. RPC_P_PACKET_CONSUMED if the packet was consumed and should
  19338. be hidden from the runtime.
  19339. RPC_S_OK if the packet was processed successfully.
  19340. RPC_S_* error if there was an error while processing the
  19341. packet.
  19342. --*/
  19343. {
  19344. HTTP2ServerOutChannel *OutChannel;
  19345. HTTP2ServerOutChannel *NewOutChannel;
  19346. HTTP2ServerInChannel *InChannel;
  19347. HTTP2ServerInChannel *InChannel2;
  19348. HTTP2ChannelPointer *ChannelPtr;
  19349. HTTP2ChannelPointer *NewChannelPtr;
  19350. HTTP2ChannelPointer *DefaultChannelPtr;
  19351. HTTP2Cookie ChannelCookie;
  19352. RPC_STATUS RpcStatus;
  19353. HTTP2SendContext *EmptyRTS;
  19354. BOOL BufferFreed;
  19355. BOOL DataReceivePosted;
  19356. HTTP2ServerOpenedPacketType PacketType;
  19357. LIST_ENTRY NewBufferHead;
  19358. HTTP2SendContext *D4_A9Context;
  19359. HTTP2SendContext *D5_A5Context;
  19360. HTTP2SendContext *D5_B1OrB2Context;
  19361. HTTP2SendContext *D2_B2Context;
  19362. ULONG BytesReceivedForAck;
  19363. ULONG WindowForAck;
  19364. HTTP2ServerOutChannelOtherCmdPacketType OutChannelPacketType;
  19365. BOOL IsOtherCmd;
  19366. ULONG PingTrafficSent;
  19367. BOOL ChannelNotSet;
  19368. BOOL ChannelRecyclingNeeded;
  19369. VerifyValidChannelId(ChannelId);
  19370. if (IsInChannel(ChannelId))
  19371. {
  19372. // in channel has an endpoint receiver. Delegate RTS and data failures to it
  19373. if (EventStatus != RPC_S_OK)
  19374. return EventStatus;
  19375. if (IsRTSPacket(Buffer))
  19376. {
  19377. RpcStatus = HTTPTransInfo->CreateThread();
  19378. if (RpcStatus != RPC_S_OK)
  19379. {
  19380. RpcFreeBuffer(Buffer);
  19381. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19382. return RPC_P_PACKET_CONSUMED;
  19383. }
  19384. BufferFreed = FALSE;
  19385. RpcStatus = CheckPacketForForwarding(Buffer,
  19386. BufferLength,
  19387. fdServer
  19388. );
  19389. if (RpcStatus == RPC_P_PACKET_NEEDS_FORWARDING)
  19390. {
  19391. // flow control acks have some weird routing. Handle
  19392. // them separately. First, test for other cmd, since it's
  19393. // cheaper
  19394. if (IsOtherCmdPacket(Buffer, BufferLength))
  19395. {
  19396. // we know this is a other cmd command. Now check for
  19397. // forwarded flow control ack
  19398. RpcStatus = ParseFlowControlAckPacketWithDestination (Buffer,
  19399. BufferLength,
  19400. fdOutProxy,
  19401. &BytesReceivedForAck,
  19402. &WindowForAck,
  19403. &ChannelCookie
  19404. );
  19405. if (RpcStatus == RPC_S_OK)
  19406. {
  19407. ChannelNotSet = FALSE;
  19408. // flow control ack. Route it based on which out channel has
  19409. // a matching cookie. It is possible that none has. That's ok -
  19410. // just drop the packet in these cases
  19411. if (OutChannelCookies[0].Compare(&ChannelCookie) == 0)
  19412. {
  19413. if (OutChannels[0].IsChannelSet())
  19414. {
  19415. RpcStatus = ForwardTrafficToChannel (
  19416. &OutChannels[0],
  19417. Buffer,
  19418. BufferLength
  19419. );
  19420. }
  19421. else
  19422. {
  19423. // see comment below where we check ChannelNotSet
  19424. ChannelNotSet = TRUE;
  19425. ASSERT(DefaultOutChannelSelector == 1);
  19426. }
  19427. }
  19428. else if (OutChannelCookies[1].Compare(&ChannelCookie) == 0)
  19429. {
  19430. if (OutChannels[1].IsChannelSet())
  19431. {
  19432. RpcStatus = ForwardTrafficToChannel (
  19433. &OutChannels[1],
  19434. Buffer,
  19435. BufferLength
  19436. );
  19437. }
  19438. else
  19439. {
  19440. // see comment below where we check ChannelNotSet
  19441. ChannelNotSet = TRUE;
  19442. ASSERT(DefaultOutChannelSelector == 0);
  19443. }
  19444. }
  19445. else
  19446. {
  19447. // fake failure - this will be handled below
  19448. RpcStatus = RPC_P_SEND_FAILED;
  19449. }
  19450. if (ChannelNotSet)
  19451. {
  19452. // we could have a match on a channel that does not exist
  19453. // if we are in D5 after D5/B1. The old channel still needs
  19454. // flow control, but the new channel cookie is current by
  19455. // now. In these cases the old channel cookie will be moved
  19456. // to the location of the cookie for the non-default channel
  19457. // Make sure this is the case. After that forward to the out proxy
  19458. // on the default channel. The out proxy will again compare cookies
  19459. // and will know which channel to forward the flow control ack to.
  19460. ASSERT(OutChannelState.State == http2svOpened);
  19461. RpcStatus = ForwardTrafficToDefaultChannel (
  19462. FALSE, // IsInChannel
  19463. Buffer,
  19464. BufferLength
  19465. );
  19466. }
  19467. // handle a recycling request if necessary
  19468. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  19469. TRUE // IsFromUpcall
  19470. );
  19471. // since forwarding may fail if channels are discarded, consume
  19472. // the packet and ignore the failure
  19473. if (RpcStatus != RPC_S_OK)
  19474. {
  19475. RpcFreeBuffer(Buffer);
  19476. RpcStatus = RPC_S_OK;
  19477. }
  19478. }
  19479. else
  19480. {
  19481. // not a forwarded flow control ack after all. Just
  19482. // forward it using normal methods
  19483. RpcStatus = ForwardTrafficToDefaultChannel(
  19484. FALSE, // IsInChannel
  19485. Buffer,
  19486. BufferLength
  19487. );
  19488. }
  19489. }
  19490. else
  19491. {
  19492. RpcStatus = ForwardTrafficToDefaultChannel(
  19493. FALSE, // IsInChannel
  19494. Buffer,
  19495. BufferLength
  19496. );
  19497. }
  19498. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  19499. TRUE // IsFromUpcall
  19500. );
  19501. if (RpcStatus != RPC_S_OK)
  19502. {
  19503. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19504. RpcFreeBuffer(Buffer);
  19505. return RPC_P_PACKET_CONSUMED;
  19506. }
  19507. // we no longer own the buffer
  19508. BufferFreed = TRUE;
  19509. }
  19510. else if (RpcStatus == RPC_S_PROTOCOL_ERROR)
  19511. {
  19512. // RTS packet is for us but is garbled
  19513. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19514. RpcFreeBuffer(Buffer);
  19515. return RPC_P_PACKET_CONSUMED;
  19516. }
  19517. else
  19518. {
  19519. RpcStatus = GetServerOpenedPacketType (Buffer,
  19520. BufferLength,
  19521. &PacketType
  19522. );
  19523. if (RpcStatus != RPC_S_OK)
  19524. {
  19525. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19526. RpcFreeBuffer(Buffer);
  19527. return RPC_P_PACKET_CONSUMED;
  19528. }
  19529. if ((PacketType == http2soptD4_A8orD5_A8) || (PacketType == http2soptD2_A6orD3_A2))
  19530. {
  19531. InChannelState.Mutex.Request();
  19532. if (PacketType == http2soptD4_A8orD5_A8)
  19533. {
  19534. // determine whether it is D4/A8 or D5/A8 based on the state
  19535. // we are in
  19536. if (OutChannelState.State == http2svOpened_A8W)
  19537. PacketType = http2soptD4_A8;
  19538. else if (OutChannelState.State == http2svOpened_D5A8W)
  19539. PacketType = http2soptD5_A8;
  19540. else
  19541. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19542. }
  19543. else
  19544. {
  19545. // determine whether it is D2/A6 or D3/A2 based on the state
  19546. // we are in
  19547. if (InChannelState.State == http2svOpened_A6W)
  19548. PacketType = http2soptD2_A6;
  19549. else if (InChannelState.State == http2svOpened)
  19550. PacketType = http2soptD3_A2;
  19551. else
  19552. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19553. }
  19554. InChannelState.Mutex.Clear();
  19555. }
  19556. if (RpcStatus != RPC_S_OK)
  19557. {
  19558. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19559. RpcFreeBuffer(Buffer);
  19560. return RPC_P_PACKET_CONSUMED;
  19561. }
  19562. switch (PacketType)
  19563. {
  19564. case http2soptD2_A6:
  19565. // this would better be D2/A6
  19566. RpcStatus = ParseAndFreeD2_A6 (Buffer,
  19567. BufferLength,
  19568. &ChannelCookie
  19569. );
  19570. BufferFreed = TRUE;
  19571. // we got D2/A6. Cancel the timeout we setup with D2/A2
  19572. CancelTimeout(GetInChannelTimer());
  19573. if (RpcStatus != RPC_S_OK)
  19574. {
  19575. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19576. return RPC_P_PACKET_CONSUMED;
  19577. }
  19578. if (InChannelCookies[GetNonDefaultInChannelSelector()].Compare(&ChannelCookie))
  19579. {
  19580. // cookies don't match - nuke the channel
  19581. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19582. return RPC_P_PACKET_CONSUMED;
  19583. }
  19584. InChannelState.Mutex.Request();
  19585. // we haven't posted a receive yet - there is no
  19586. // way the state of the channel will change
  19587. ASSERT(InChannelState.State == http2svOpened_A6W);
  19588. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened_B1W, 1, 0);
  19589. InChannelState.State = http2svOpened_B1W;
  19590. InChannelState.Mutex.Clear();
  19591. break;
  19592. case http2soptD3_A2:
  19593. if (IsDefaultInChannel(ChannelId) == FALSE)
  19594. {
  19595. ASSERT(0);
  19596. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19597. RpcFreeBuffer(Buffer);
  19598. return RPC_P_PACKET_CONSUMED;
  19599. }
  19600. RpcStatus = ParseAndFreeD3_A2 (Buffer,
  19601. BufferLength,
  19602. &ChannelCookie
  19603. );
  19604. BufferFreed = TRUE;
  19605. if (RpcStatus != RPC_S_OK)
  19606. {
  19607. AbortChannels(RpcStatus);
  19608. return RPC_P_PACKET_CONSUMED;
  19609. }
  19610. // update the passed in cookie
  19611. InChannelCookies[DefaultInChannelSelector].SetCookie(ChannelCookie.GetCookie());
  19612. // pass D3/A3 back
  19613. EmptyRTS = AllocateAndInitializeEmptyRTSWithDestination (fdClient);
  19614. if (EmptyRTS == NULL)
  19615. {
  19616. AbortChannels(RpcStatus);
  19617. return RPC_P_PACKET_CONSUMED;
  19618. }
  19619. RpcStatus = SendTrafficOnDefaultChannel (FALSE, // IsInChannel
  19620. EmptyRTS
  19621. );
  19622. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  19623. TRUE // IsFromUpcall
  19624. );
  19625. break;
  19626. case http2soptD2_B1:
  19627. InChannelState.Mutex.Request();
  19628. if (InChannelState.State != http2svOpened_B1W)
  19629. {
  19630. InChannelState.Mutex.Clear();
  19631. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19632. RpcFreeBuffer(Buffer);
  19633. return RPC_P_PACKET_CONSUMED;
  19634. }
  19635. InChannelState.Mutex.Clear();
  19636. RpcStatus = ParseAndFreeEmptyRTS(Buffer,
  19637. BufferLength);
  19638. // we no longer own the buffer
  19639. BufferFreed = TRUE;
  19640. if (RpcStatus != RPC_S_OK)
  19641. {
  19642. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19643. return RPC_P_PACKET_CONSUMED;
  19644. }
  19645. // we're done with this channel. We want to switch
  19646. // channels and destroy
  19647. // and detach the channel.
  19648. SwitchDefaultInChannelSelector();
  19649. ChannelPtr = GetChannelPointerFromId(ChannelId);
  19650. InChannel = (HTTP2ServerInChannel *)ChannelPtr->LockChannelPointer();
  19651. if (InChannel == NULL)
  19652. {
  19653. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19654. return RPC_P_PACKET_CONSUMED;
  19655. }
  19656. InChannel2 = LockDefaultInChannel(&NewChannelPtr);
  19657. if (InChannel2 == NULL)
  19658. {
  19659. ChannelPtr->UnlockChannelPointer();
  19660. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19661. return RPC_P_PACKET_CONSUMED;
  19662. }
  19663. DataReceivePosted = InChannel->IsDataReceivePosted();
  19664. RpcStatus = InChannel->TransferReceiveStateToNewChannel(InChannel2);
  19665. NewChannelPtr->UnlockChannelPointer();
  19666. ChannelPtr->UnlockChannelPointer();
  19667. if (RpcStatus != RPC_S_OK)
  19668. {
  19669. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19670. return RPC_P_PACKET_CONSUMED;
  19671. }
  19672. D2_B2Context = AllocateAndInitializeD2_B2 (HTTP2ServerReceiveWindow);
  19673. if (D2_B2Context == NULL)
  19674. {
  19675. AbortChannels(RPC_S_OUT_OF_MEMORY);
  19676. return RPC_P_PACKET_CONSUMED;
  19677. }
  19678. // now that we have transferred the settings, we can open
  19679. // the pipeline from the new in proxy
  19680. RpcStatus = SendTrafficOnDefaultChannel(TRUE, // IsInChannel
  19681. D2_B2Context
  19682. );
  19683. if (RpcStatus != RPC_S_OK)
  19684. {
  19685. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19686. FreeRTSPacket(D2_B2Context);
  19687. return RPC_P_PACKET_CONSUMED;
  19688. }
  19689. // detach, abort and free lifetime reference
  19690. ChannelPtr->FreeChannelPointer(TRUE, // DrainUpCalls
  19691. TRUE, // CalledFromUpcallContext
  19692. TRUE, // Abort
  19693. RPC_P_CONNECTION_SHUTDOWN
  19694. );
  19695. InChannelState.Mutex.Request();
  19696. // we haven't posted a receive yet - there is no
  19697. // way the state of the channel will change
  19698. ASSERT(InChannelState.State == http2svOpened_B1W);
  19699. LogEvent(SU_HTTPv2, EV_STATE, this, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  19700. InChannelState.State = http2svOpened;
  19701. InChannelState.Mutex.Clear();
  19702. if (DataReceivePosted)
  19703. {
  19704. RpcStatus = PostReceiveOnDefaultChannel (
  19705. TRUE, // IsInChannel
  19706. http2ttData
  19707. );
  19708. if (RpcStatus != RPC_S_OK)
  19709. {
  19710. AbortChannels(RPC_S_PROTOCOL_ERROR);
  19711. }
  19712. }
  19713. return RPC_P_PACKET_CONSUMED;
  19714. break;
  19715. case http2soptD4_A8:
  19716. // verify the new cookie against the old, and execute
  19717. // the detachment of the old channel after sending D4_A9
  19718. InChannelState.Mutex.Request();
  19719. if (OutChannelState.State != http2svOpened_A8W)
  19720. {
  19721. InChannelState.Mutex.Clear();
  19722. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19723. break;
  19724. }
  19725. // move back to opened state
  19726. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  19727. OutChannelState.State = http2svOpened;
  19728. InChannelState.Mutex.Clear();
  19729. RpcStatus = ParseAndFreeD4_A8 (Buffer,
  19730. BufferLength,
  19731. fdServer,
  19732. &ChannelCookie
  19733. );
  19734. BufferFreed = TRUE;
  19735. // we got D4/A8. Cancel the timeout we setup with D4/A4
  19736. CancelTimeout(GetOutChannelTimer());
  19737. if (RpcStatus != RPC_S_OK)
  19738. break;
  19739. if (OutChannelCookies[GetNonDefaultOutChannelSelector()].Compare(&ChannelCookie))
  19740. {
  19741. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19742. break;
  19743. }
  19744. // lock the old channel
  19745. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  19746. if (OutChannel == NULL)
  19747. {
  19748. RpcStatus = RPC_P_CONNECTION_CLOSED;
  19749. break;
  19750. }
  19751. // switch channels (new channel is still plugged)
  19752. SwitchDefaultOutChannelSelector();
  19753. // wait for all submits to get out of old channel
  19754. OutChannel->DrainPendingSubmissions();
  19755. // leave 1 for our lock
  19756. ChannelPtr->DrainPendingLocks(1);
  19757. // lock new channel (by now it is default)
  19758. NewOutChannel = LockDefaultOutChannel(&NewChannelPtr);
  19759. if (NewOutChannel == NULL)
  19760. {
  19761. ChannelPtr->UnlockChannelPointer();
  19762. RpcStatus = RPC_P_CONNECTION_CLOSED;
  19763. break;
  19764. }
  19765. // if flow control sender was queuing, grab all its buffers as well.
  19766. // Note that the flow control sender is higher in the stack and must
  19767. // be done first (to preserve packet ordering)
  19768. RpcpInitializeListHead(&NewBufferHead);
  19769. RpcStatus = OutChannel->GetFlowControlSenderBufferQueue(&NewBufferHead);
  19770. if (RpcStatus != RPC_S_OK)
  19771. {
  19772. // if we couldn't get the send contexts, they would have been
  19773. // freed in GetFlowControlSenderBufferQueue
  19774. NewChannelPtr->UnlockChannelPointer();
  19775. ChannelPtr->UnlockChannelPointer();
  19776. break;
  19777. }
  19778. AddBufferQueueToChannel(&NewBufferHead, NewOutChannel);
  19779. // GetChannelOriginatorBufferQueue must be called in submission
  19780. // context only. Get there
  19781. RpcStatus = OutChannel->BeginSimpleSubmitAsync();
  19782. if (RpcStatus != RPC_S_OK)
  19783. {
  19784. NewChannelPtr->UnlockChannelPointer();
  19785. ChannelPtr->UnlockChannelPointer();
  19786. break;
  19787. }
  19788. // if old channel was queuing, grab all its buffers. Since it is
  19789. // below the flow control sender, we must do it second to make sure
  19790. // they are before the flow control sender's buffers
  19791. RpcpInitializeListHead(&NewBufferHead);
  19792. RpcStatus = OutChannel->GetChannelOriginatorBufferQueue(&NewBufferHead);
  19793. OutChannel->FinishSubmitAsync();
  19794. if (RpcStatus != RPC_S_OK)
  19795. {
  19796. // if we couldn't get the send contexts, they would have been
  19797. // freed in GetChannelOriginatorBufferQueue
  19798. NewChannelPtr->UnlockChannelPointer();
  19799. ChannelPtr->UnlockChannelPointer();
  19800. break;
  19801. }
  19802. AddBufferQueueToChannel(&NewBufferHead, NewOutChannel);
  19803. // register the last packet to send with the old channel
  19804. D4_A9Context = AllocateAndInitializeD4_A9 ();
  19805. if (D4_A9Context == NULL)
  19806. {
  19807. ChannelPtr->UnlockChannelPointer();
  19808. NewChannelPtr->UnlockChannelPointer();
  19809. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19810. break;
  19811. }
  19812. RpcStatus = OutChannel->Send(D4_A9Context);
  19813. if (RpcStatus != RPC_S_OK)
  19814. {
  19815. ChannelPtr->UnlockChannelPointer();
  19816. NewChannelPtr->UnlockChannelPointer();
  19817. FreeRTSPacket(D4_A9Context);
  19818. break;
  19819. }
  19820. // D4_A9 was sent. We must switch the
  19821. // default loopback and detach the channel.
  19822. // Note that we don't abort the channel - we
  19823. // just release the lifetime reference
  19824. // When the proxy closes the connection, then
  19825. // we will abort
  19826. ChannelPtr->UnlockChannelPointer();
  19827. RpcStatus = NewOutChannel->Unplug();
  19828. NewChannelPtr->UnlockChannelPointer();
  19829. if (RpcStatus != RPC_S_OK)
  19830. break;
  19831. RpcStatus = RPC_P_PACKET_CONSUMED;
  19832. break;
  19833. case http2soptD5_A8:
  19834. // verify the new cookie against the old, and execute
  19835. // the detachment of the old channel after sending D4_A9
  19836. InChannelState.Mutex.Request();
  19837. if (OutChannelState.State != http2svOpened_D5A8W)
  19838. {
  19839. InChannelState.Mutex.Clear();
  19840. RpcStatus = RPC_S_PROTOCOL_ERROR;
  19841. break;
  19842. }
  19843. RpcStatus = ParseAndFreeD5_A8 (Buffer,
  19844. BufferLength,
  19845. fdServer,
  19846. &ChannelCookie
  19847. );
  19848. BufferFreed = TRUE;
  19849. CancelTimeout(GetOutChannelTimer());
  19850. if (RpcStatus != RPC_S_OK)
  19851. {
  19852. InChannelState.Mutex.Clear();
  19853. break;
  19854. }
  19855. // we use the non-default out channel cookie simply as temporary storage
  19856. // b/n D5/A4 and D5/A8
  19857. if (OutChannelCookies[GetNonDefaultOutChannelSelector()].Compare(&ChannelCookie))
  19858. {
  19859. // the new channel is fake. Tell the proxy about it, and it will ditch it
  19860. D5_B1OrB2Context = AllocateAndInitializeD5_B1orB2 (FALSE);
  19861. if (D5_B1OrB2Context == NULL)
  19862. {
  19863. InChannelState.Mutex.Clear();
  19864. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19865. break;
  19866. }
  19867. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  19868. D5_B1OrB2Context);
  19869. if (RpcStatus != RPC_S_OK)
  19870. {
  19871. InChannelState.Mutex.Clear();
  19872. FreeRTSPacket(D5_B1OrB2Context);
  19873. break;
  19874. }
  19875. // move back to opened state
  19876. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  19877. OutChannelState.State = http2svOpened;
  19878. InChannelState.Mutex.Clear();
  19879. break;
  19880. }
  19881. // the cookie matches. Move the new channel cookie from temporary to permanent
  19882. // storage and move the old channel cookie to temp storage
  19883. // move old cookie to temp storage
  19884. ChannelCookie.SetCookie(
  19885. OutChannelCookies[DefaultOutChannelSelector].GetCookie());
  19886. // move new cookie from class temp storage to permanent storage
  19887. OutChannelCookies[DefaultOutChannelSelector].SetCookie (
  19888. OutChannelCookies[GetNonDefaultOutChannelSelector()].GetCookie());
  19889. // move the old cookie from local temporary storage to class temporary storage
  19890. OutChannelCookies[GetNonDefaultOutChannelSelector()].SetCookie (
  19891. ChannelCookie.GetCookie());
  19892. // move back to opened state
  19893. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  19894. OutChannelState.State = http2svOpened;
  19895. InChannelState.Mutex.Clear();
  19896. OutChannel = LockDefaultOutChannel(&ChannelPtr);
  19897. if (OutChannel == NULL)
  19898. {
  19899. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  19900. break;
  19901. }
  19902. OutChannel->PlugDataOriginatorChannel();
  19903. // Wait for everybody that was in to get out. This way we know
  19904. // the channel was plugged.
  19905. // we know that this will complete because eventually the runtime
  19906. // will flow control itself if there is no lull in sent traffic
  19907. OutChannel->DrainPendingSubmissions();
  19908. D5_B1OrB2Context = AllocateAndInitializeD5_B1orB2 (TRUE);
  19909. if (D5_B1OrB2Context == NULL)
  19910. {
  19911. ChannelPtr->UnlockChannelPointer();
  19912. RpcStatus = RPC_S_OUT_OF_MEMORY;
  19913. break;
  19914. }
  19915. RpcStatus = OutChannel->Send(D5_B1OrB2Context);
  19916. if (RpcStatus != RPC_S_OK)
  19917. {
  19918. ChannelPtr->UnlockChannelPointer();
  19919. FreeRTSPacket(D5_B1OrB2Context);
  19920. break;
  19921. }
  19922. RpcStatus = OutChannel->RestartDataOriginatorChannel();
  19923. ChannelPtr->UnlockChannelPointer();
  19924. // fall through the error code
  19925. break;
  19926. default:
  19927. ASSERT(0);
  19928. break;
  19929. }
  19930. }
  19931. RpcStatus = PostReceiveOnDefaultChannel(
  19932. TRUE, // IsInChannel
  19933. http2ttRTS
  19934. );
  19935. if (RpcStatus != RPC_S_OK)
  19936. AbortChannels(RPC_P_CONNECTION_CLOSED);
  19937. if (BufferFreed == FALSE)
  19938. RpcFreeBuffer(Buffer);
  19939. return RPC_P_PACKET_CONSUMED;
  19940. }
  19941. else
  19942. {
  19943. return EventStatus;
  19944. }
  19945. }
  19946. else
  19947. {
  19948. if (EventStatus != RPC_S_OK)
  19949. {
  19950. if (IsDefaultOutChannel(ChannelId) == FALSE)
  19951. {
  19952. InChannelState.Mutex.Request();
  19953. if ( (OutChannelState.State == http2svOpened)
  19954. || (OutChannelState.State == http2svNonDefaultChannelCloseWait))
  19955. {
  19956. // were in state where we were delaying recycling of the channel
  19957. // until the non-default channel is closed? See
  19958. // HTTP2ServerVirtualConnection::RecycleChannel for more
  19959. // information
  19960. if (OutChannelState.State == http2svNonDefaultChannelCloseWait)
  19961. {
  19962. ChannelRecyclingNeeded = TRUE;
  19963. OutChannelState.State = http2svOpened;
  19964. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened, 1, 0);
  19965. }
  19966. else
  19967. ChannelRecyclingNeeded = FALSE;
  19968. // close on the non-default channel in open
  19969. // state is not an error. Just discard the channel
  19970. InChannelState.Mutex.Clear();
  19971. ChannelPtr = GetChannelPointerFromId(ChannelId);
  19972. if (ChannelPtr == NULL)
  19973. {
  19974. // This should never happen.
  19975. ASSERT(0);
  19976. return RPC_S_INTERNAL_ERROR;
  19977. }
  19978. if (ChannelRecyclingNeeded)
  19979. {
  19980. // we are currently on the non-default channel. Once we free it,
  19981. // we have nothing to keep the virtual connection alive while
  19982. // we trigger recycling. In order to protect the virtual
  19983. // connection from disappearing, we must get a second lock before
  19984. // we free our channel - Rule 39.
  19985. if (LockDefaultOutChannel(&DefaultChannelPtr) == NULL)
  19986. {
  19987. // the default out channel is gone - the connection is being
  19988. // aborted. Ignore the channel recycling and just bail out after
  19989. // cleanup
  19990. ASSERT(IsAborted());
  19991. ChannelRecyclingNeeded = FALSE;
  19992. // fall through. Next we will abort the channel and since
  19993. // ChannelRecyclingNeeded is FALSE, just bail out
  19994. }
  19995. }
  19996. OutChannel = (HTTP2ServerOutChannel *)ChannelPtr->LockChannelPointer();
  19997. if (OutChannel)
  19998. {
  19999. // make sure the pending sends are drained. Otherwise
  20000. // a send that is currently completing may violate
  20001. // rule 38
  20002. OutChannel->DrainPendingSends();
  20003. ChannelPtr->UnlockChannelPointer();
  20004. }
  20005. ChannelPtr->FreeChannelPointer(
  20006. TRUE, // DrainUpcalls
  20007. TRUE, // CalledFromUpcallContext
  20008. TRUE, // Abort
  20009. RPC_P_CONNECTION_SHUTDOWN
  20010. );
  20011. if (ChannelRecyclingNeeded)
  20012. {
  20013. RpcStatus = RecycleChannel(
  20014. TRUE // IsFromUpcall
  20015. );
  20016. if (RpcStatus != RPC_S_OK)
  20017. {
  20018. AbortChannels(RpcStatus);
  20019. // fall through to consuming the packet and returning.
  20020. // Since the channels are aborted, the pending operaitons
  20021. // will come back and abort the connection.
  20022. }
  20023. DefaultChannelPtr->UnlockChannelPointer();
  20024. }
  20025. RpcStatus = RPC_P_PACKET_CONSUMED;
  20026. BufferFreed = TRUE;
  20027. return RpcStatus;
  20028. }
  20029. else
  20030. InChannelState.Mutex.Clear();
  20031. }
  20032. else if (InChannelState.State == http2svB2W)
  20033. {
  20034. // if this is a half open connection, treat
  20035. // this as data receive and indicate it to the
  20036. // runtime
  20037. AbortChannels(EventStatus);
  20038. // if we are still in this state, return error to the
  20039. // runtime. Else, somebody else joined and we can ignore
  20040. // this error
  20041. InChannelState.Mutex.Request();
  20042. if (InChannelState.State == http2svB2W)
  20043. {
  20044. // convert the state to closed. This is necessary so that
  20045. // if the in channel finally comes, it finds a closed
  20046. // connection and doesn't try to open it.
  20047. InChannelState.State = http2svClosed;
  20048. // Leave EventStatus as it is and fall through
  20049. }
  20050. else
  20051. {
  20052. // consume the receive
  20053. EventStatus = RPC_P_PACKET_CONSUMED;
  20054. }
  20055. InChannelState.Mutex.Clear();
  20056. return EventStatus;
  20057. }
  20058. AbortChannels(EventStatus);
  20059. // we expect only RTS traffic on this channel. Nobody would post
  20060. // a data receive on this channel. Consume the receive
  20061. return RPC_P_PACKET_CONSUMED;
  20062. }
  20063. if (IsRTSPacket(Buffer))
  20064. {
  20065. RpcStatus = HTTPTransInfo->CreateThread();
  20066. if (RpcStatus != RPC_S_OK)
  20067. {
  20068. RpcFreeBuffer(Buffer);
  20069. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20070. return RPC_P_PACKET_CONSUMED;
  20071. }
  20072. IsOtherCmd = IsOtherCmdPacket(Buffer,
  20073. BufferLength
  20074. );
  20075. RpcStatus = GetServerOutChannelOtherCmdPacketType (
  20076. Buffer,
  20077. BufferLength,
  20078. &OutChannelPacketType
  20079. );
  20080. if (RpcStatus != RPC_S_OK)
  20081. {
  20082. RpcFreeBuffer(Buffer);
  20083. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20084. return RPC_P_PACKET_CONSUMED;
  20085. }
  20086. if (IsOtherCmd && (OutChannelPacketType == http2sococptFlowControl))
  20087. {
  20088. RpcStatus = ParseAndFreeFlowControlAckPacket (Buffer,
  20089. BufferLength,
  20090. &BytesReceivedForAck,
  20091. &WindowForAck,
  20092. &ChannelCookie
  20093. );
  20094. if (RpcStatus == RPC_S_OK)
  20095. {
  20096. // notify the flow control sender
  20097. ChannelPtr = GetChannelPointerFromId(ChannelId);
  20098. OutChannel = (HTTP2ServerOutChannel *)ChannelPtr->LockChannelPointer();
  20099. // forward acks only on default channels. Non-default channels
  20100. // will have all their buffers transfered to the new channel in the
  20101. // immediate future. If we forward to them, we can cause nasty
  20102. // race conditions as another thread tries to get channels out of them
  20103. if (IsDefaultOutChannel(ChannelId))
  20104. {
  20105. if (OutChannel == NULL)
  20106. {
  20107. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  20108. return RPC_P_PACKET_CONSUMED;
  20109. }
  20110. RpcStatus = OutChannel->FlowControlAckNotify(BytesReceivedForAck,
  20111. WindowForAck
  20112. );
  20113. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  20114. TRUE // IsFromUpcall
  20115. );
  20116. }
  20117. ChannelPtr->UnlockChannelPointer();
  20118. if (RpcStatus == RPC_S_OK)
  20119. {
  20120. // post another receive
  20121. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  20122. http2ttRaw
  20123. );
  20124. }
  20125. }
  20126. if (RpcStatus != RPC_S_OK)
  20127. {
  20128. AbortChannels(RpcStatus);
  20129. }
  20130. }
  20131. else if (IsOtherCmd && (OutChannelPacketType == http2sococptPingTrafficSentNotify))
  20132. {
  20133. RpcStatus = ParseAndFreePingTrafficSentNotifyPacket (Buffer,
  20134. BufferLength,
  20135. &PingTrafficSent
  20136. );
  20137. if (RpcStatus == RPC_S_OK)
  20138. {
  20139. // notify the channel data originator
  20140. ChannelPtr = GetChannelPointerFromId(ChannelId);
  20141. OutChannel = (HTTP2ServerOutChannel *)ChannelPtr->LockChannelPointer();
  20142. if (OutChannel == NULL)
  20143. {
  20144. AbortChannels(RPC_P_CONNECTION_SHUTDOWN);
  20145. return RPC_P_PACKET_CONSUMED;
  20146. }
  20147. // prevent bogus values from the proxy. We allow no more than
  20148. // approximately MaxBytesSentByProxy bytes per BytesSentByProxyTimeInterval.
  20149. // The exact calculation doesn't matter. This requirement is so much below
  20150. // the bar necessary to attack the server, that anything close to it makes
  20151. // us safe
  20152. if (BytesSentByProxyTimeIntervalStart == 0)
  20153. BytesSentByProxyTimeIntervalStart = NtGetTickCount();
  20154. else
  20155. {
  20156. if (NtGetTickCount() - BytesSentByProxyTimeIntervalStart > BytesSentByProxyTimeInterval)
  20157. {
  20158. // start a new interval
  20159. BytesSentByProxyTimeIntervalStart = NtGetTickCount();
  20160. BytesSentByProxyForInterval = PingTrafficSent;
  20161. }
  20162. else
  20163. {
  20164. BytesSentByProxyForInterval += PingTrafficSent;
  20165. }
  20166. if (BytesSentByProxyForInterval > MaxBytesSentByProxy)
  20167. {
  20168. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20169. return RPC_P_PACKET_CONSUMED;
  20170. }
  20171. }
  20172. RpcStatus = OutChannel->NotifyDataOriginatorForTrafficSent (PingTrafficSent);
  20173. RpcStatus = StartChannelRecyclingIfNecessary(RpcStatus,
  20174. TRUE // IsFromUpcall
  20175. );
  20176. ChannelPtr->UnlockChannelPointer();
  20177. if (RpcStatus == RPC_S_OK)
  20178. {
  20179. // post another receive
  20180. RpcStatus = PostReceiveOnChannel(GetChannelPointerFromId(ChannelId),
  20181. http2ttRaw
  20182. );
  20183. }
  20184. }
  20185. if (RpcStatus != RPC_S_OK)
  20186. {
  20187. AbortChannels(RpcStatus);
  20188. }
  20189. }
  20190. else
  20191. {
  20192. // the only packet we expect here is D5/A4
  20193. // we must be in Opened_A4W state for it
  20194. InChannelState.Mutex.Request();
  20195. if (OutChannelState.State != http2svOpened_A4W)
  20196. {
  20197. InChannelState.Mutex.Clear();
  20198. RpcFreeBuffer(Buffer);
  20199. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20200. return RPC_P_PACKET_CONSUMED;
  20201. }
  20202. RpcStatus = ParseAndFreeD5_A4 (Buffer,
  20203. BufferLength,
  20204. &OutChannelCookies[GetNonDefaultOutChannelSelector()]
  20205. );
  20206. if (RpcStatus != RPC_S_OK)
  20207. {
  20208. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20209. InChannelState.Mutex.Clear();
  20210. return RPC_P_PACKET_CONSUMED;
  20211. }
  20212. // move to Opened_A8W state
  20213. LogEvent(SU_HTTPv2, EV_STATE, this, OUT_CHANNEL_STATE, http2svOpened_D5A8W, 1, 0);
  20214. OutChannelState.State = http2svOpened_D5A8W;
  20215. InChannelState.Mutex.Clear();
  20216. RpcStatus = SetTimeout(DefaultNoResponseTimeout, GetOutChannelTimer());
  20217. if (RpcStatus != RPC_S_OK)
  20218. {
  20219. AbortChannels(RpcStatus);
  20220. return RPC_P_PACKET_CONSUMED;
  20221. }
  20222. // send out D5/A5
  20223. D5_A5Context = AllocateAndInitializeD5_A5 (fdClient);
  20224. if (D5_A5Context == NULL)
  20225. {
  20226. AbortChannels(RPC_S_OUT_OF_MEMORY);
  20227. return RPC_P_PACKET_CONSUMED;
  20228. }
  20229. RpcStatus = SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  20230. D5_A5Context
  20231. );
  20232. if (RpcStatus != RPC_S_OK)
  20233. {
  20234. AbortChannels(RPC_S_OUT_OF_MEMORY);
  20235. FreeRTSPacket(D5_A5Context);
  20236. return RPC_P_PACKET_CONSUMED;
  20237. }
  20238. RpcStatus = PostReceiveOnDefaultChannel(FALSE, // IsInChannel
  20239. http2ttRaw
  20240. );
  20241. if (RpcStatus != RPC_S_OK)
  20242. AbortChannels(RpcStatus);
  20243. }
  20244. return RPC_P_PACKET_CONSUMED;
  20245. }
  20246. else
  20247. {
  20248. // we shouldn't receive non-RTS packets on the out channel on the
  20249. // server
  20250. AbortChannels(RPC_S_PROTOCOL_ERROR);
  20251. return RPC_P_PACKET_CONSUMED;
  20252. }
  20253. }
  20254. }
  20255. RPC_STATUS HTTP2ServerVirtualConnection::SyncSend (
  20256. IN ULONG BufferLength,
  20257. IN BYTE *Buffer,
  20258. IN BOOL fDisableShutdownCheck,
  20259. IN BOOL fDisableCancelCheck,
  20260. IN ULONG Timeout
  20261. )
  20262. /*++
  20263. Routine Description:
  20264. Does a sync send on a server HTTP connection.
  20265. Arguments:
  20266. BufferLength - the length of the data to send.
  20267. Buffer - the data to send.
  20268. fDisableShutdownCheck - ignored
  20269. fDisableCancelCheck - runtime indicates no cancel
  20270. will be attempted on this send. Can be used
  20271. as optimization hint by the transport
  20272. Timeout - send timeout (call timeout)
  20273. Return Value:
  20274. RPC_S_OK for success or RPC_S_* / Win32 error for failure
  20275. --*/
  20276. {
  20277. RPC_STATUS RpcStatus;
  20278. RPC_STATUS RpcStatus2;
  20279. HTTP2SendContext *SendContext;
  20280. HTTP2ServerOutChannel *Channel;
  20281. HTTP2ChannelPointer *ChannelPtr;
  20282. #if DBG
  20283. InChannelState.Mutex.Request();
  20284. if ((OutChannelState.State == http2svOpened)
  20285. || (OutChannelState.State == http2svNonDefaultChannelCloseWait) )
  20286. {
  20287. VerifyTimerNotSet(GetOutChannelTimer());
  20288. }
  20289. InChannelState.Mutex.Clear();
  20290. #endif
  20291. // if the caller did not set a last buffer to free, we can't abandon the send
  20292. // because we can't cleanup. Wait for the send to complete.
  20293. if (IsLastBufferToFreeSet() == FALSE)
  20294. {
  20295. return HTTP2VirtualConnection::SyncSend (BufferLength,
  20296. Buffer,
  20297. fDisableShutdownCheck,
  20298. fDisableCancelCheck,
  20299. Timeout
  20300. );
  20301. }
  20302. // we will complete this as an async send behind the covers
  20303. // and we will fake success unless the submission itself
  20304. // fails
  20305. Channel = (HTTP2ServerOutChannel *)LockDefaultSendChannel (&ChannelPtr);
  20306. if (Channel == NULL)
  20307. {
  20308. return RPC_P_SEND_FAILED;
  20309. }
  20310. SendContext = Channel->GetLastSendContext();
  20311. if (SendContext == NULL)
  20312. {
  20313. ChannelPtr->UnlockChannelPointer();
  20314. return RPC_S_OUT_OF_MEMORY;
  20315. }
  20316. SendContext->u.BufferToFree = GetAndResetLastBufferToFree();
  20317. SendContext->SetListEntryUnused();
  20318. SendContext->maxWriteBuffer = BufferLength;
  20319. SendContext->pWriteBuffer = Buffer;
  20320. // SendContext->Write.pAsyncObject = NULL; // this will be initialized in the bottom layer
  20321. SendContext->Write.ol.Internal = STATUS_PENDING;
  20322. SendContext->TrafficType = http2ttData;
  20323. SendContext->Write.ol.OffsetHigh = 0;
  20324. // Clear any stale flags in case the context has been cached.
  20325. SendContext->Flags = SendContextFlagAbandonedSend;
  20326. SendContext->UserData = 0;
  20327. RpcStatus = Channel->Send(SendContext);
  20328. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  20329. {
  20330. // synchronous failure - cleanup
  20331. RpcFreeBuffer(SendContext->u.BufferToFree);
  20332. Channel->FreeLastSendContext(SendContext);
  20333. }
  20334. ChannelPtr->UnlockChannelPointer();
  20335. //
  20336. // If Send() returns RPC_P_CHANNEL_NEEDS_RECYCLING, then the SendContext
  20337. // has been queued in HTTP2ChannelDataOriginator::Send() in BufferQueue
  20338. // and HTTP2ChannelDataOriginator::Abort() will fail it later by posting
  20339. // CHANNEL_DATA_ORIGINATOR_DIRECT_SEND in the case of communication breakdown.
  20340. //
  20341. // We should make sure the send completes at most once. Therefore, if we know
  20342. // the send context will be taken off the queue during the abort, we will mask this
  20343. // syncronous failure.
  20344. //
  20345. if (RpcStatus == RPC_P_CHANNEL_NEEDS_RECYCLING)
  20346. {
  20347. // make sure there is a thread to pick up the recycling events
  20348. RpcStatus = HTTPTransInfo->CreateThread();
  20349. if (RpcStatus != RPC_S_OK)
  20350. {
  20351. VALIDATE(RpcStatus)
  20352. {
  20353. RPC_S_OK,
  20354. RPC_S_OUT_OF_MEMORY,
  20355. RPC_S_OUT_OF_RESOURCES,
  20356. RPC_P_SEND_FAILED,
  20357. RPC_S_CALL_CANCELLED,
  20358. RPC_P_RECEIVE_COMPLETE,
  20359. RPC_P_TIMEOUT
  20360. } END_VALIDATE;
  20361. // REVIEW: We may want to think what happens with the queued SendContext.
  20362. // It may or may not get completed in this case. Ideally, we would want
  20363. // make sure that it will not complete if we are going to fail syncronously.
  20364. return RpcStatus;
  20365. }
  20366. // get the ball rolling with the recycle
  20367. RpcStatus = RecycleChannel(
  20368. FALSE // IsFromUpcall
  20369. );
  20370. VALIDATE(RpcStatus)
  20371. {
  20372. RPC_S_OK,
  20373. RPC_S_OUT_OF_MEMORY,
  20374. RPC_S_OUT_OF_RESOURCES,
  20375. RPC_S_CALL_CANCELLED,
  20376. RPC_P_SEND_FAILED,
  20377. RPC_P_RECEIVE_FAILED,
  20378. RPC_P_CONNECTION_SHUTDOWN,
  20379. RPC_P_CONNECTION_CLOSED,
  20380. RPC_P_TIMEOUT
  20381. } END_VALIDATE;
  20382. // Supress the sync failure. The failure will be returned
  20383. // during the abort on the completion of the queued send.
  20384. if (RpcStatus != RPC_S_OK)
  20385. {
  20386. RpcStatus = RPC_S_OK;
  20387. }
  20388. }
  20389. // Note that send can't really fail with protocol error. When
  20390. // it happens it has simply picked the error with which
  20391. // the connection was aborted. This is as good as a failed send.
  20392. if ((RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
  20393. || (RpcStatus == RPC_P_RECEIVE_FAILED)
  20394. || (RpcStatus == RPC_P_CONNECTION_CLOSED)
  20395. || (RpcStatus == RPC_S_PROTOCOL_ERROR))
  20396. RpcStatus = RPC_P_SEND_FAILED;
  20397. VALIDATE(RpcStatus)
  20398. {
  20399. RPC_S_OK,
  20400. RPC_S_OUT_OF_MEMORY,
  20401. RPC_S_OUT_OF_RESOURCES,
  20402. RPC_P_SEND_FAILED,
  20403. RPC_S_CALL_CANCELLED,
  20404. RPC_P_RECEIVE_COMPLETE,
  20405. RPC_P_TIMEOUT
  20406. } END_VALIDATE;
  20407. return RpcStatus;
  20408. }
  20409. RPC_STATUS HTTP2ServerVirtualConnection::InitializeServerConnection (
  20410. IN BYTE *Packet,
  20411. IN ULONG PacketLength,
  20412. IN WS_HTTP2_INITIAL_CONNECTION *Connection,
  20413. OUT HTTP2ServerVirtualConnection **ServerVirtualConnection,
  20414. OUT BOOL *VirtualConnectionCreated
  20415. )
  20416. /*++
  20417. Routine Description:
  20418. Initializes a server connection. Based on the content of the
  20419. packet (i.e. D1/A2 or D1/B2), it will either initialize the
  20420. out channel or the in channel respectively, and if it is
  20421. the first leg of the connection establishment, establish the
  20422. virtual connection itself and insert it into the cookie table
  20423. Note: This function must initialize the type member and migrate the
  20424. WS_HTTP2_INITIAL_CONNECTION after morphing it into
  20425. WS_HTTP2_CONNECTION. The VirtualConnectionCreated parameter indicates
  20426. whether this was done.
  20427. Arguments:
  20428. Packet - received packet. Guaranteed to be present until PacketLength.
  20429. On second leg, this function must not free the buffer. Ownership
  20430. of the buffer remains with the caller.
  20431. PacketLength - the lenght of the received packet.
  20432. Connection - the received connection. It must be migrated
  20433. and morphed into WS_HTTP2_CONNECTION on success. If the virtual
  20434. connection was already created, then returning failure without
  20435. un-migrating is fine. Cleanup paths will check and recognize this
  20436. as HTTP2ServerVirtualConnection.
  20437. ServerVirtualConnection - on successful return, the created server virtual
  20438. connection
  20439. VirtualConnectionCreated - if non-zero, the WS_HTTP2_INITIAL_CONNECTION
  20440. was morphed into virtual connection. Else, the WS_HTTP2_INITIAL_CONNECTION
  20441. is still around. Must be set on success and failure.
  20442. Return Value:
  20443. RPC_S_OK or RPC_S_* for error. If we return RPC_S_OK, the packet will be
  20444. consumed by caller. If we return anything else, it won't be.
  20445. --*/
  20446. {
  20447. RPC_STATUS RpcStatus;
  20448. RPC_STATUS RpcStatus2;
  20449. HTTP2FirstServerPacketType PacketType;
  20450. WS_HTTP2_INITIAL_CONNECTION *OriginalConnection = Connection;
  20451. HTTP2ServerInChannel *InChannel = NULL;
  20452. HTTP2ServerOutChannel *OutChannel = NULL;
  20453. HTTP2ServerCookie ServerCookie;
  20454. HTTP2Cookie ChannelCookie;
  20455. HTTP2Cookie NewChannelCookie;
  20456. ULONG OutProxyReceiveWindow;
  20457. ULONG ProtocolVersion;
  20458. ULONG OutChannelLifetime;
  20459. ULONG InProxyReceiveWindow;
  20460. ULONG InProxyConnectionTimeout;
  20461. ULONG OutProxyConnectionTimeout;
  20462. HTTP2Cookie AssociationGroupId;
  20463. ChannelSettingClientAddress ClientAddress;
  20464. HTTP2ServerVirtualConnection *LocalServerConnection;
  20465. HTTP2ServerVirtualConnection *VCPlaceHolder;
  20466. BOOL FirstLeg;
  20467. BOOL AbortServerConnection = FALSE;
  20468. HTTP2ServerChannel *ThisChannel;
  20469. HTTP2ChannelPointer *OtherChannelPtr;
  20470. HTTP2SendContext *D1_C1Context;
  20471. HTTP2SendContext *D1_B3Context;
  20472. HTTP2SendContext *D2_A3Context;
  20473. HTTP2SendContext *D4_A4Context;
  20474. HTTP2SendContext *D4_A5Context;
  20475. int NonDefaultChannel;
  20476. *VirtualConnectionCreated = FALSE;
  20477. // First, do a little bit of parsing to
  20478. // determine if this is the first request for this connection
  20479. // cookie. If not, join the other connection and destroy the
  20480. // runtime stuff for this one. If yes, build a virtual connection
  20481. RpcStatus = GetFirstServerPacketType(Packet,
  20482. PacketLength,
  20483. &PacketType
  20484. );
  20485. if (RpcStatus != RPC_S_OK)
  20486. {
  20487. // packet with failure will be propagated to the runtime
  20488. return RpcStatus;
  20489. }
  20490. if (PacketType == http2fsptD1_A2)
  20491. {
  20492. RpcStatus = ParseD1_A2(Packet,
  20493. PacketLength,
  20494. &ProtocolVersion,
  20495. &ServerCookie,
  20496. &ChannelCookie,
  20497. &OutChannelLifetime,
  20498. &OutProxyReceiveWindow);
  20499. if (RpcStatus != RPC_S_OK)
  20500. return RpcStatus;
  20501. if (OutChannelLifetime < MinimumChannelLifetime)
  20502. return RPC_S_PROTOCOL_ERROR;
  20503. // a request to establish a new out connection
  20504. RpcStatus = AllocateAndInitializeOutChannel (&Connection,
  20505. OutChannelLifetime,
  20506. &OutChannel);
  20507. if (RpcStatus == RPC_S_OK)
  20508. {
  20509. // unplug the newly created out channel
  20510. RpcStatus2 = OutChannel->Unplug ();
  20511. // we know we can't fail here since there are no data in the pipe line
  20512. ASSERT(RpcStatus2 == RPC_S_OK);
  20513. OutChannel->SetPeerReceiveWindow(OutProxyReceiveWindow);
  20514. }
  20515. }
  20516. else if (PacketType == http2fsptD1_B2)
  20517. {
  20518. RpcpMemorySet(&ClientAddress, 0, sizeof(ClientAddress));
  20519. RpcStatus = ParseD1_B2(Packet,
  20520. PacketLength,
  20521. &ProtocolVersion,
  20522. &ServerCookie,
  20523. &ChannelCookie,
  20524. &InProxyReceiveWindow,
  20525. &InProxyConnectionTimeout,
  20526. &AssociationGroupId,
  20527. &ClientAddress
  20528. );
  20529. if (RpcStatus != RPC_S_OK)
  20530. return RpcStatus;
  20531. // a request to establish a new in connection
  20532. RpcStatus = AllocateAndInitializeInChannel (&Connection,
  20533. &InChannel);
  20534. }
  20535. else if (PacketType == http2fsptD2_A2)
  20536. {
  20537. // in channel replacement
  20538. RpcStatus = ParseD2_A2(Packet,
  20539. PacketLength,
  20540. &ProtocolVersion,
  20541. &ServerCookie,
  20542. &ChannelCookie,
  20543. &NewChannelCookie,
  20544. &InProxyReceiveWindow,
  20545. &InProxyConnectionTimeout
  20546. );
  20547. if (RpcStatus != RPC_S_OK)
  20548. return RpcStatus;
  20549. // a request to establish a replacement in connection
  20550. RpcStatus = AllocateAndInitializeInChannel (&Connection,
  20551. &InChannel);
  20552. }
  20553. else
  20554. {
  20555. ASSERT(PacketType == http2fsptD4_A4);
  20556. // out channel replacement
  20557. RpcStatus = ParseD4_A4(Packet,
  20558. PacketLength,
  20559. &ProtocolVersion,
  20560. &ServerCookie,
  20561. &ChannelCookie,
  20562. &NewChannelCookie,
  20563. &OutChannelLifetime,
  20564. &OutProxyReceiveWindow,
  20565. &OutProxyConnectionTimeout
  20566. );
  20567. if (RpcStatus != RPC_S_OK)
  20568. return RpcStatus;
  20569. // a request to establish a replacement out connection
  20570. RpcStatus = AllocateAndInitializeOutChannel (&Connection,
  20571. OutChannelLifetime,
  20572. &OutChannel);
  20573. if (RpcStatus == RPC_S_OK)
  20574. OutChannel->SetPeerReceiveWindow(OutProxyReceiveWindow);
  20575. }
  20576. if (RpcStatus != RPC_S_OK)
  20577. return RpcStatus;
  20578. // take the lower of our and reported version
  20579. ProtocolVersion = min(ProtocolVersion, HTTP2ProtocolVersion);
  20580. // add the raw connection to the PnP list
  20581. TransportProtocol::AddObjectToProtocolList(Connection);
  20582. // figure out whether we arrived first or second
  20583. GetServerCookieCollection()->LockCollection();
  20584. LocalServerConnection =
  20585. (HTTP2ServerVirtualConnection *)GetServerCookieCollection()->FindElement(&ServerCookie);
  20586. if (((PacketType == http2fsptD2_A2) || (PacketType == http2fsptD4_A4))
  20587. && (LocalServerConnection == NULL))
  20588. {
  20589. // we cannot establish a replacement connection if the old one is not around
  20590. OriginalConnection->fAborted = 1;
  20591. OriginalConnection->pReadBuffer = NULL;
  20592. RpcStatus = RPC_P_RECEIVE_FAILED;
  20593. goto AbortFirstLegAndExit;
  20594. }
  20595. if (LocalServerConnection == NULL)
  20596. {
  20597. // we're first. Initialize the server virtual connection
  20598. // we know the server has reserved space for the larger of
  20599. // WS_HTTP2_INITIAL_CONNECTION and HTTP2ServerVirtualConnection.
  20600. // Use the same space.
  20601. VCPlaceHolder = (HTTP2ServerVirtualConnection *)OriginalConnection;
  20602. LocalServerConnection = new (VCPlaceHolder) HTTP2ServerVirtualConnection(&ServerCookie,
  20603. ProtocolVersion,
  20604. &RpcStatus);
  20605. if (RpcStatus == RPC_S_OK)
  20606. {
  20607. // we use the first timer for connection establishment
  20608. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout,
  20609. LocalServerConnection->GetInChannelTimer());
  20610. }
  20611. if (RpcStatus != RPC_S_OK)
  20612. {
  20613. LocalServerConnection->HTTP2ServerVirtualConnection::~HTTP2ServerVirtualConnection();
  20614. OriginalConnection->fAborted = 1;
  20615. OriginalConnection->pReadBuffer = NULL;
  20616. goto AbortFirstLegAndExit;
  20617. }
  20618. *VirtualConnectionCreated = TRUE;
  20619. LocalServerConnection->id = HTTPv2;
  20620. LocalServerConnection->type = COMPLEX_T | SERVER;
  20621. FirstLeg = TRUE;
  20622. }
  20623. else
  20624. {
  20625. // the actual transport connection is by now owned by the channel
  20626. // Create a fake connection in the current location that will no-op on
  20627. // close.
  20628. OriginalConnection->fAborted = 1;
  20629. OriginalConnection->pReadBuffer = NULL;
  20630. if (PacketType == http2fsptD2_A2)
  20631. {
  20632. // if this is a replacement channel, check the cookies
  20633. if (LocalServerConnection->CompareCookieWithDefaultInChannelCookie(&ChannelCookie))
  20634. {
  20635. // cookies don't match. Nuke the newly established channel - it is probably
  20636. // fake
  20637. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20638. goto AbortFirstLegAndExit;
  20639. }
  20640. // we still hold the cookie collection mutex. This synchronizes with
  20641. // aborts
  20642. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout,
  20643. LocalServerConnection->GetInChannelTimer());
  20644. if (RpcStatus != RPC_S_OK)
  20645. goto AbortFirstLegAndExit;
  20646. }
  20647. else if (PacketType == http2fsptD4_A4)
  20648. {
  20649. // if this is a replacement channel, check the cookies
  20650. if (LocalServerConnection->CompareCookieWithDefaultOutChannelCookie(&ChannelCookie))
  20651. {
  20652. // cookies don't match. Nuke the newly established channel - it is probably
  20653. // fake
  20654. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20655. goto AbortFirstLegAndExit;
  20656. }
  20657. // we still hold the cookie collection mutex. This synchronizes with
  20658. // aborts
  20659. RpcStatus = LocalServerConnection->SetTimeout(DefaultNoResponseTimeout,
  20660. LocalServerConnection->GetOutChannelTimer());
  20661. if (RpcStatus != RPC_S_OK)
  20662. goto AbortFirstLegAndExit;
  20663. }
  20664. FirstLeg = FALSE;
  20665. }
  20666. // set the runtime connection ptr for the raw connection
  20667. Connection->RuntimeConnectionPtr = LocalServerConnection;
  20668. LocalServerConnection->ProtocolVersion = min (ProtocolVersion, LocalServerConnection->ProtocolVersion);
  20669. if (PacketType == http2fsptD1_A2)
  20670. {
  20671. if (LocalServerConnection->OutChannels[0].IsChannelSet())
  20672. {
  20673. // if we already have a second channel, then this is a protocol error
  20674. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20675. goto AbortSecondLegAndExit;
  20676. }
  20677. LocalServerConnection->OutProxySettings[0].ReceiveWindow = OutProxyReceiveWindow;
  20678. LocalServerConnection->OutProxySettings[0].ChannelLifetime = OutChannelLifetime;
  20679. LocalServerConnection->OutChannelCookies[0].SetCookie(ChannelCookie.GetCookie());
  20680. // attach the newly created stack to the connection
  20681. LocalServerConnection->SetFirstOutChannel(OutChannel);
  20682. OutChannel->SetParent(LocalServerConnection);
  20683. if (FirstLeg)
  20684. {
  20685. ASSERT(LocalServerConnection->InChannelState.State == http2svClosed);
  20686. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svB2W, 1, 0);
  20687. LocalServerConnection->InChannelState.State = http2svB2W;
  20688. GetServerCookieCollection()->AddElement(&LocalServerConnection->EmbeddedConnectionCookie);
  20689. }
  20690. else
  20691. {
  20692. // we got the second leg - cancel the timeout for the second leg
  20693. LocalServerConnection->CancelTimeout(LocalServerConnection->GetInChannelTimer());
  20694. if (LocalServerConnection->InChannelState.State != http2svA2W)
  20695. {
  20696. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20697. goto AbortSecondLegAndExit;
  20698. }
  20699. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  20700. LocalServerConnection->InChannelState.State = http2svOpened;
  20701. LocalServerConnection->OutChannelState.State = http2svOpened;
  20702. ASSERT(InChannel == NULL);
  20703. InChannel = LocalServerConnection->LockDefaultInChannel(&OtherChannelPtr);
  20704. if (InChannel == NULL)
  20705. {
  20706. RpcStatus = RPC_P_RECEIVE_FAILED;
  20707. goto AbortSecondLegAndExit;
  20708. }
  20709. InChannel->AddReference();
  20710. OtherChannelPtr->UnlockChannelPointer();
  20711. // for second leg, we need to add one reference before we release
  20712. // the lock. Otherwise the pending receive on the first leg may
  20713. // kill the connection and the channel with it
  20714. OutChannel->AddReference();
  20715. }
  20716. }
  20717. else if ((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD2_A2))
  20718. {
  20719. if (PacketType == http2fsptD1_B2)
  20720. {
  20721. if (FirstLeg == FALSE)
  20722. {
  20723. // we got the second leg - cancel the timeout for the second leg
  20724. LocalServerConnection->CancelTimeout(LocalServerConnection->GetInChannelTimer());
  20725. }
  20726. CopyClientAddress(&LocalServerConnection->ClientAddress,
  20727. &ClientAddress);
  20728. LocalServerConnection->InProxyReceiveWindows[0] = InProxyReceiveWindow;
  20729. LocalServerConnection->InProxyConnectionTimeout = InProxyConnectionTimeout;
  20730. LocalServerConnection->AssociationGroupId.SetCookie(AssociationGroupId.GetCookie());
  20731. LocalServerConnection->InChannelCookies[0].SetCookie(ChannelCookie.GetCookie());
  20732. // attach the newly created stack to the connection
  20733. LocalServerConnection->SetFirstInChannel(InChannel);
  20734. InChannel->SetParent(LocalServerConnection);
  20735. }
  20736. else
  20737. {
  20738. ASSERT(PacketType == http2fsptD2_A2);
  20739. NonDefaultChannel = LocalServerConnection->GetNonDefaultInChannelSelector();
  20740. LocalServerConnection->InProxyReceiveWindows[NonDefaultChannel] = InProxyReceiveWindow;
  20741. LocalServerConnection->InProxyConnectionTimeout = InProxyConnectionTimeout;
  20742. LocalServerConnection->InChannelCookies[NonDefaultChannel].SetCookie(NewChannelCookie.GetCookie());
  20743. // attach the newly created stack to the connection
  20744. LocalServerConnection->SetNonDefaultInChannel(InChannel);
  20745. InChannel->SetParent(LocalServerConnection);
  20746. if (LocalServerConnection->InChannelState.State != http2svOpened)
  20747. {
  20748. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20749. goto AbortSecondLegAndExit;
  20750. }
  20751. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened_A6W, 1, 0);
  20752. LocalServerConnection->InChannelState.State = http2svOpened_A6W;
  20753. ASSERT(FirstLeg == FALSE);
  20754. }
  20755. if (FirstLeg)
  20756. {
  20757. ASSERT(LocalServerConnection->InChannelState.State == http2svClosed);
  20758. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svA2W, 1, 0);
  20759. LocalServerConnection->InChannelState.State = http2svA2W;
  20760. GetServerCookieCollection()->AddElement(&LocalServerConnection->EmbeddedConnectionCookie);
  20761. }
  20762. else
  20763. {
  20764. if (PacketType == http2fsptD1_B2)
  20765. {
  20766. if (LocalServerConnection->InChannelState.State != http2svB2W)
  20767. {
  20768. // this can happen if the out channel managed to attach
  20769. // itself and then die
  20770. RpcStatus = RPC_P_RECEIVE_FAILED;
  20771. goto AbortSecondLegAndExit;
  20772. }
  20773. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, IN_CHANNEL_STATE, http2svOpened, 1, 0);
  20774. LocalServerConnection->InChannelState.State = http2svOpened;
  20775. LocalServerConnection->OutChannelState.State = http2svOpened;
  20776. }
  20777. else
  20778. {
  20779. ASSERT(PacketType == http2fsptD2_A2);
  20780. }
  20781. ASSERT(OutChannel == NULL);
  20782. OutChannel = LocalServerConnection->LockDefaultOutChannel(&OtherChannelPtr);
  20783. if (OutChannel == NULL)
  20784. {
  20785. RpcStatus = RPC_P_RECEIVE_FAILED;
  20786. goto AbortSecondLegAndExit;
  20787. }
  20788. OutChannel->AddReference();
  20789. OtherChannelPtr->UnlockChannelPointer();
  20790. // for second leg, we need to add one reference before we release
  20791. // the lock. Otherwise the pending receive on the first leg may
  20792. // kill the connection and the channel with it
  20793. InChannel->AddReference();
  20794. }
  20795. }
  20796. else if (PacketType == http2fsptD4_A4)
  20797. {
  20798. NonDefaultChannel = LocalServerConnection->GetNonDefaultOutChannelSelector();
  20799. LocalServerConnection->OutProxySettings[NonDefaultChannel].ReceiveWindow = OutProxyReceiveWindow;
  20800. LocalServerConnection->OutChannelCookies[NonDefaultChannel].SetCookie(NewChannelCookie.GetCookie());
  20801. // attach the newly created stack to the connection
  20802. LocalServerConnection->SetNonDefaultOutChannel(OutChannel);
  20803. OutChannel->SetParent(LocalServerConnection);
  20804. if (LocalServerConnection->OutChannelState.State != http2svOpened_A4W)
  20805. {
  20806. RpcStatus = RPC_S_PROTOCOL_ERROR;
  20807. goto AbortSecondLegAndExit;
  20808. }
  20809. LogEvent(SU_HTTPv2, EV_STATE, LocalServerConnection, OUT_CHANNEL_STATE, http2svOpened_A8W, 1, 0);
  20810. LocalServerConnection->OutChannelState.State = http2svOpened_A8W;
  20811. ASSERT(FirstLeg == FALSE);
  20812. ASSERT(InChannel == NULL);
  20813. InChannel = LocalServerConnection->LockDefaultInChannel(&OtherChannelPtr);
  20814. if (InChannel == NULL)
  20815. {
  20816. RpcStatus = RPC_P_RECEIVE_FAILED;
  20817. goto AbortSecondLegAndExit;
  20818. }
  20819. InChannel->AddReference();
  20820. OtherChannelPtr->UnlockChannelPointer();
  20821. // for second leg, we need to add one reference before we release
  20822. // the lock. Otherwise the pending receive on the first leg may
  20823. // kill the connection and the channel with it
  20824. OutChannel->AddReference();
  20825. }
  20826. else
  20827. {
  20828. ASSERT(0);
  20829. }
  20830. // we have a virtual connection and at least one of its channels
  20831. // attached to it. We have a no-op connection in OriginalConnection
  20832. // by now. Any failure paths on the second leg must abort the virtual connection
  20833. if ((PacketType == http2fsptD1_A2) || (PacketType == http2fsptD4_A4))
  20834. {
  20835. // out channel
  20836. RpcStatus = OutChannel->Receive(http2ttRaw);
  20837. ThisChannel = OutChannel;
  20838. }
  20839. else
  20840. {
  20841. ASSERT((PacketType == http2fsptD1_B2)
  20842. || (PacketType == http2fsptD2_A2) );
  20843. // in channel
  20844. RpcStatus = InChannel->Receive(http2ttRTS);
  20845. if ((PacketType == http2fsptD1_B2) && (RpcStatus == RPC_S_OK))
  20846. {
  20847. // naturally, we're also interested in data receives
  20848. RpcStatus = InChannel->Receive(http2ttData);
  20849. }
  20850. ThisChannel = InChannel;
  20851. }
  20852. // Make sure HTTP2ServerVirtualConnection didn't forget to
  20853. // initialize its type member
  20854. if (FirstLeg && RpcStatus == RPC_S_OK)
  20855. {
  20856. ASSERT(LocalServerConnection->id == HTTPv2);
  20857. ASSERT(LocalServerConnection->type & COMPLEX_T);
  20858. }
  20859. // Release the lock after posting a raw receive in order to syncronize the receive with
  20860. // the in channel establishment.
  20861. GetServerCookieCollection()->UnlockCollection();
  20862. if (FirstLeg)
  20863. {
  20864. // this is the first leg. We know we are the only ones parting on
  20865. // the connection. In case of error just return it back. The runtime
  20866. // will turn around and close the connection
  20867. }
  20868. else
  20869. {
  20870. if ((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD1_A2))
  20871. {
  20872. // the connection is fully fleshed out and both channels are plugged. Some
  20873. // additional activity remains. We need to abort the runtime connection
  20874. // for the second leg and remove the extra refcount
  20875. if (RpcStatus == RPC_S_OK)
  20876. {
  20877. // we need to re-obtain the local server connection pointer through a safe mechanism.
  20878. // After we released the collection mutex, it may have been destroyed
  20879. LocalServerConnection = (HTTP2ServerVirtualConnection *) InChannel->LockParentPointer();
  20880. if (LocalServerConnection)
  20881. {
  20882. // we successfully submitted receives. Now send out D1/C1 and D1/B3
  20883. D1_C1Context = AllocateAndInitializeD1_C1(LocalServerConnection->ProtocolVersion,
  20884. LocalServerConnection->InProxyReceiveWindows[0],
  20885. LocalServerConnection->InProxyConnectionTimeout
  20886. );
  20887. if (D1_C1Context != NULL)
  20888. {
  20889. // we don't need to lock it, because we have a reference to it
  20890. RpcStatus = OutChannel->Send(D1_C1Context);
  20891. if (RpcStatus == RPC_S_OK)
  20892. {
  20893. D1_B3Context = AllocateAndInitializeD1_B3(HTTP2ServerReceiveWindow,
  20894. LocalServerConnection->ProtocolVersion
  20895. );
  20896. if (D1_B3Context != NULL)
  20897. {
  20898. RpcStatus = InChannel->Send(D1_B3Context);
  20899. if (RpcStatus != RPC_S_OK)
  20900. FreeRTSPacket(D1_B3Context);
  20901. }
  20902. else
  20903. {
  20904. RpcStatus = RPC_S_OUT_OF_MEMORY;
  20905. }
  20906. }
  20907. else
  20908. {
  20909. FreeRTSPacket(D1_C1Context);
  20910. }
  20911. }
  20912. else
  20913. {
  20914. RpcStatus = RPC_S_OUT_OF_MEMORY;
  20915. }
  20916. InChannel->UnlockParentPointer();
  20917. }
  20918. else
  20919. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  20920. }
  20921. }
  20922. else if (PacketType == http2fsptD2_A2)
  20923. {
  20924. // We have added the second channel to the connection. Keep the ball
  20925. // rolling
  20926. if (RpcStatus == RPC_S_OK)
  20927. {
  20928. // After we released the collection mutex, it may have been destroyed
  20929. LocalServerConnection = (HTTP2ServerVirtualConnection *) OutChannel->LockParentPointer();
  20930. if (LocalServerConnection)
  20931. {
  20932. // we successfully submitted receives. Now send out D2/A3
  20933. D2_A3Context = AllocateAndInitializeD2_A3(fdClient,
  20934. LocalServerConnection->ProtocolVersion,
  20935. LocalServerConnection->InProxyReceiveWindows[NonDefaultChannel],
  20936. LocalServerConnection->InProxyConnectionTimeout
  20937. );
  20938. if (D2_A3Context != NULL)
  20939. {
  20940. // we don't need to lock it, because we have a reference to it.
  20941. RpcStatus = OutChannel->Send(D2_A3Context);
  20942. if ((RpcStatus != RPC_S_OK)
  20943. && (RpcStatus != RPC_P_CHANNEL_NEEDS_RECYCLING))
  20944. {
  20945. FreeRTSPacket(D2_A3Context);
  20946. }
  20947. // handle a recycling request if necessary
  20948. RpcStatus = LocalServerConnection->StartChannelRecyclingIfNecessary(RpcStatus,
  20949. FALSE // IsFromUpcall
  20950. );
  20951. }
  20952. else
  20953. {
  20954. RpcStatus = RPC_S_OUT_OF_MEMORY;
  20955. }
  20956. OutChannel->UnlockParentPointer();
  20957. }
  20958. else
  20959. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  20960. }
  20961. }
  20962. else
  20963. {
  20964. ASSERT(PacketType == http2fsptD4_A4);
  20965. // We have added the second channel to the connection. Keep the ball
  20966. // rolling
  20967. if (RpcStatus == RPC_S_OK)
  20968. {
  20969. // After we released the collection mutex, it may have been destroyed
  20970. LocalServerConnection = (HTTP2ServerVirtualConnection *) OutChannel->LockParentPointer();
  20971. if (LocalServerConnection)
  20972. {
  20973. // we successfully submitted receives. Now send out D4/A5
  20974. D4_A5Context = AllocateAndInitializeD4_A5(fdClient,
  20975. LocalServerConnection->ProtocolVersion,
  20976. OutProxyConnectionTimeout
  20977. );
  20978. if (D4_A5Context != NULL)
  20979. {
  20980. // We still need to send on the default channel. Obtain
  20981. // a pointer through the virtual connection
  20982. RpcStatus = LocalServerConnection->SendTrafficOnDefaultChannel(FALSE, // IsInChannel
  20983. D4_A5Context
  20984. );
  20985. if (RpcStatus != RPC_S_OK)
  20986. FreeRTSPacket(D4_A5Context);
  20987. }
  20988. else
  20989. {
  20990. RpcStatus = RPC_S_OUT_OF_MEMORY;
  20991. }
  20992. OutChannel->UnlockParentPointer();
  20993. }
  20994. else
  20995. RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
  20996. }
  20997. }
  20998. if (RpcStatus != RPC_S_OK)
  20999. {
  21000. // we can't directly access the connection because we don't have
  21001. // a way to prevent it from going away underneath us. We do it through
  21002. // the channels instead (on which we do have a refcount)
  21003. LocalServerConnection = (HTTP2ServerVirtualConnection *)ThisChannel->LockParentPointer();
  21004. if (LocalServerConnection)
  21005. {
  21006. LocalServerConnection->AbortChannels(RpcStatus);
  21007. ThisChannel->UnlockParentPointer();
  21008. }
  21009. }
  21010. InChannel->RemoveReference();
  21011. OutChannel->RemoveReference();
  21012. if (RpcStatus == RPC_S_OK)
  21013. {
  21014. // fake failure to the runtime. We have migrated our transport connection
  21015. // to the virtual connection and we don't need this one anymore
  21016. RpcStatus = RPC_P_RECEIVE_FAILED;
  21017. }
  21018. }
  21019. return RpcStatus;
  21020. AbortSecondLegAndExit:
  21021. ASSERT(FirstLeg == FALSE);
  21022. LocalServerConnection->Abort();
  21023. GetServerCookieCollection()->UnlockCollection();
  21024. // We do not need to unlink the added connection from the PnP list
  21025. // since this will be done on Free().
  21026. // the original connection must be WS_HTTP2_INITIAL_CONNECTION
  21027. ASSERT(OriginalConnection->id == HTTP);
  21028. ASSERT(RpcStatus != RPC_S_OK);
  21029. return RpcStatus;
  21030. AbortFirstLegAndExit:
  21031. // we failed to create a server connection. Release all locks and fail
  21032. GetServerCookieCollection()->UnlockCollection();
  21033. // the original connection must be WS_HTTP2_INITIAL_CONNECTION
  21034. ASSERT(OriginalConnection->id == HTTP);
  21035. // destroy the channel created during the first leg
  21036. if ((PacketType == http2fsptD1_A2) || (PacketType == http2fsptD4_A4))
  21037. {
  21038. OutChannel->Abort(RpcStatus);
  21039. OutChannel->RemoveReference();
  21040. }
  21041. else
  21042. {
  21043. ASSERT((PacketType == http2fsptD1_B2) || (PacketType == http2fsptD2_A2));
  21044. InChannel->Abort(RpcStatus);
  21045. InChannel->RemoveReference();
  21046. }
  21047. ASSERT(RpcStatus != RPC_S_OK);
  21048. return RpcStatus;
  21049. }
  21050. RPC_STATUS HTTP2ServerVirtualConnection::AllocateAndInitializeInChannel (
  21051. IN OUT WS_HTTP2_INITIAL_CONNECTION **Connection,
  21052. OUT HTTP2ServerInChannel **ReturnInChannel
  21053. )
  21054. /*++
  21055. Routine Description:
  21056. Initializes a server in channel.
  21057. Note: This function must migrate the WS_HTTP2_INITIAL_CONNECTION after
  21058. morphing it into WS_HTTP2_CONNECTION
  21059. Arguments:
  21060. Connection - on input, the received connection. It must be migrated
  21061. and morphed into WS_HTTP2_CONNECTION on success. All failure paths
  21062. must be sure to move the WS_HTTP2_INITIAL_CONNECTION back to its
  21063. original location.
  21064. ReturnInChannel - on successful return, the created server in channel
  21065. Return Value:
  21066. RPC_S_OK or RPC_S_* for error
  21067. --*/
  21068. {
  21069. ULONG MemorySize;
  21070. BYTE *MemoryBlock, *CurrentBlock;
  21071. HTTP2ServerInChannel *InChannel;
  21072. HTTP2EndpointReceiver *EndpointReceiver;
  21073. HTTP2SocketTransportChannel *RawChannel;
  21074. WS_HTTP2_CONNECTION *RawConnection;
  21075. BOOL EndpointReceiverNeedsCleanup;
  21076. BOOL RawChannelNeedsCleanup;
  21077. RPC_STATUS RpcStatus;
  21078. // alocate the in channel
  21079. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerInChannel)
  21080. + SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver)
  21081. + SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  21082. + sizeof(WS_HTTP2_CONNECTION);
  21083. MemoryBlock = (BYTE *) new char [MemorySize];
  21084. CurrentBlock = MemoryBlock;
  21085. if (CurrentBlock == NULL)
  21086. return RPC_S_OUT_OF_MEMORY;
  21087. InChannel = (HTTP2ServerInChannel *) MemoryBlock;
  21088. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerInChannel);
  21089. EndpointReceiver = (HTTP2EndpointReceiver *) CurrentBlock;
  21090. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2EndpointReceiver);
  21091. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  21092. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  21093. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  21094. // all memory blocks are allocated. Go and initialize them. Use explicit
  21095. // placement
  21096. EndpointReceiverNeedsCleanup = FALSE;
  21097. RawChannelNeedsCleanup = FALSE;
  21098. // Wait for any pending IO to get out.
  21099. while((*Connection)->IsIoStarting())
  21100. Sleep(1);
  21101. RpcpMemoryCopy(RawConnection, *Connection, sizeof(WS_HTTP2_CONNECTION));
  21102. RawConnection->HeaderRead = TRUE;
  21103. RawConnection->ReadHeaderFn = NULL;
  21104. RawConnection->Read.pAsyncObject = RawConnection;
  21105. RawConnection->type = COMPLEX_T | CONNECTION | SERVER;
  21106. RawConnection->fAborted = 1; // this connection must not be aborted
  21107. // unless we successfully initialize
  21108. // the channel. Therefore, artificially
  21109. // abort the connection (preventing real
  21110. // aborts) until we initialize the channel
  21111. // Since Initialize() is not called, we need to init fIgnoreFree explicitly.
  21112. RawConnection->fIgnoreFree = FALSE;
  21113. RawConnection = new (RawConnection) WS_HTTP2_CONNECTION;
  21114. RpcStatus = RPC_S_OK;
  21115. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  21116. if (RpcStatus != RPC_S_OK)
  21117. {
  21118. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  21119. goto AbortAndExit;
  21120. }
  21121. RawConnection->Channel = RawChannel;
  21122. RawChannelNeedsCleanup = TRUE;
  21123. EndpointReceiver = new (EndpointReceiver) HTTP2EndpointReceiver (HTTP2ServerReceiveWindow,
  21124. TRUE, // IsServer
  21125. &RpcStatus);
  21126. if (RpcStatus != RPC_S_OK)
  21127. {
  21128. EndpointReceiver->HTTP2EndpointReceiver::~HTTP2EndpointReceiver();
  21129. goto AbortAndExit;
  21130. }
  21131. RawChannel->SetUpperChannel(EndpointReceiver);
  21132. EndpointReceiver->SetLowerChannel(RawChannel);
  21133. EndpointReceiverNeedsCleanup = TRUE;
  21134. InChannel = new (InChannel) HTTP2ServerInChannel (&RpcStatus);
  21135. if (RpcStatus != RPC_S_OK)
  21136. {
  21137. InChannel->HTTP2ServerInChannel::~HTTP2ServerInChannel();
  21138. goto AbortAndExit;
  21139. }
  21140. EndpointReceiver->SetUpperChannel(InChannel);
  21141. InChannel->SetLowerChannel(EndpointReceiver);
  21142. RawChannel->SetTopChannel(InChannel);
  21143. EndpointReceiver->SetTopChannel(InChannel);
  21144. ASSERT(RpcStatus == RPC_S_OK);
  21145. RawConnection->fAborted = 0;
  21146. *ReturnInChannel = InChannel;
  21147. *Connection = (WS_HTTP2_INITIAL_CONNECTION *)RawConnection;
  21148. goto CleanupAndExit;
  21149. AbortAndExit:
  21150. // No need to clean up the raw connection.
  21151. // If we failed, the virtual connection
  21152. // is not created, and the caller will abort
  21153. // the original conneciton.
  21154. //
  21155. // We need to make sure that this failure path
  21156. // will not try freeing the raw connection.
  21157. // For this we set fIgnoreFree to true to ensure that
  21158. // the free will be ignored.
  21159. ASSERT(RpcStatus != RPC_S_OK);
  21160. RawConnection->fIgnoreFree = TRUE;
  21161. if (EndpointReceiverNeedsCleanup)
  21162. {
  21163. EndpointReceiver->Abort(RpcStatus);
  21164. EndpointReceiver->FreeObject();
  21165. }
  21166. else if (RawChannelNeedsCleanup)
  21167. {
  21168. RawChannel->Abort(RpcStatus);
  21169. RawChannel->FreeObject();
  21170. }
  21171. RawConnection->fIgnoreFree = FALSE;
  21172. if (MemoryBlock)
  21173. delete [] MemoryBlock;
  21174. CleanupAndExit:
  21175. return RpcStatus;
  21176. }
  21177. RPC_STATUS HTTP2ServerVirtualConnection::AllocateAndInitializeOutChannel (
  21178. IN OUT WS_HTTP2_INITIAL_CONNECTION **Connection,
  21179. IN ULONG OutChannelLifetime,
  21180. OUT HTTP2ServerOutChannel **ReturnOutChannel
  21181. )
  21182. /*++
  21183. Routine Description:
  21184. Initializes a server out channel.
  21185. Note: This function must migrate the WS_HTTP2_INITIAL_CONNECTION after
  21186. morphing it into WS_HTTP2_CONNECTION
  21187. Arguments:
  21188. Connection - on input, the received connection. It must be migrated
  21189. and morphed into WS_HTTP2_CONNECTION on success. All failure paths
  21190. must be sure to move the WS_HTTP2_INITIAL_CONNECTION back to its
  21191. original location.
  21192. OutChannelLifetime - the lifetime on the out channel.
  21193. ReturnOutChannel - on successful return, the created server out channel
  21194. Return Value:
  21195. RPC_S_OK or RPC_S_* for error
  21196. --*/
  21197. {
  21198. ULONG MemorySize;
  21199. BYTE *MemoryBlock, *CurrentBlock;
  21200. HTTP2ServerOutChannel *OutChannel;
  21201. HTTP2PlugChannel *PlugChannel;
  21202. HTTP2FlowControlSender *FlowControlSender;
  21203. HTTP2ChannelDataOriginator *ChannelDataOriginator;
  21204. HTTP2SocketTransportChannel *RawChannel;
  21205. WS_HTTP2_CONNECTION *RawConnection;
  21206. BOOL PlugChannelNeedsCleanup;
  21207. BOOL FlowControlSenderNeedsCleanup;
  21208. BOOL ChannelDataOriginatorNeedsCleanup;
  21209. BOOL RawChannelNeedsCleanup;
  21210. RPC_STATUS RpcStatus;
  21211. // alocate the out channel
  21212. MemorySize = SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerOutChannel)
  21213. + SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel)
  21214. + SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender)
  21215. + SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator)
  21216. + SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel)
  21217. + SIZE_OF_OBJECT_AND_PADDING(WS_HTTP2_CONNECTION)
  21218. + sizeof(HTTP2SendContext) // send context for the last send
  21219. ;
  21220. MemoryBlock = (BYTE *) new char [MemorySize];
  21221. CurrentBlock = MemoryBlock;
  21222. if (CurrentBlock == NULL)
  21223. return RPC_S_OUT_OF_MEMORY;
  21224. OutChannel = (HTTP2ServerOutChannel *) MemoryBlock;
  21225. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ServerOutChannel);
  21226. PlugChannel = (HTTP2PlugChannel *) CurrentBlock;
  21227. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2PlugChannel);
  21228. FlowControlSender = (HTTP2FlowControlSender *) CurrentBlock;
  21229. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2FlowControlSender);
  21230. ChannelDataOriginator = (HTTP2ChannelDataOriginator *)CurrentBlock;
  21231. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2ChannelDataOriginator);
  21232. RawChannel = (HTTP2SocketTransportChannel *)CurrentBlock;
  21233. CurrentBlock += SIZE_OF_OBJECT_AND_PADDING(HTTP2SocketTransportChannel);
  21234. RawConnection = (WS_HTTP2_CONNECTION *)CurrentBlock;
  21235. // all memory blocks are allocated. Go and initialize them. Use explicit
  21236. // placement
  21237. PlugChannelNeedsCleanup = FALSE;
  21238. FlowControlSenderNeedsCleanup = FALSE;
  21239. ChannelDataOriginatorNeedsCleanup = FALSE;
  21240. RawChannelNeedsCleanup = FALSE;
  21241. // migrate the connection to its new location. Since nobody points to it (we have
  21242. // been unlinked from the PnP list), copying is sufficient
  21243. // Wait for any pending IO to get out.
  21244. while((*Connection)->IsIoStarting())
  21245. Sleep(1);
  21246. RpcpMemoryCopy(RawConnection, *Connection, sizeof(WS_HTTP2_CONNECTION));
  21247. RawConnection->HeaderRead = TRUE;
  21248. RawConnection->Read.pAsyncObject = RawConnection;
  21249. RawConnection->type = COMPLEX_T | CONNECTION | SERVER;
  21250. RawConnection->fAborted = 1; // this connection must not be aborted
  21251. // unless we successfully initialize
  21252. // the channel. Therefore, artificially
  21253. // abort the connection (preventing real
  21254. // aborts) until we initialize the channel
  21255. // Since Initialize() is not called, we need to init fIgnoreFree explicitly.
  21256. RawConnection->fIgnoreFree = FALSE;
  21257. RawConnection = new (RawConnection) WS_HTTP2_CONNECTION;
  21258. RpcStatus = RPC_S_OK;
  21259. RawChannel = new (RawChannel) HTTP2SocketTransportChannel (RawConnection, &RpcStatus);
  21260. if (RpcStatus != RPC_S_OK)
  21261. {
  21262. RawChannel->HTTP2SocketTransportChannel::~HTTP2SocketTransportChannel();
  21263. goto AbortAndExit;
  21264. }
  21265. RawConnection->Channel = RawChannel;
  21266. RawChannelNeedsCleanup = TRUE;
  21267. ChannelDataOriginator = new (ChannelDataOriginator) HTTP2ChannelDataOriginator (OutChannelLifetime,
  21268. TRUE, // IsServer
  21269. &RpcStatus);
  21270. if (RpcStatus != RPC_S_OK)
  21271. {
  21272. ChannelDataOriginator->HTTP2ChannelDataOriginator::~HTTP2ChannelDataOriginator();
  21273. goto AbortAndExit;
  21274. }
  21275. RawChannel->SetUpperChannel(ChannelDataOriginator);
  21276. ChannelDataOriginator->SetLowerChannel(RawChannel);
  21277. ChannelDataOriginatorNeedsCleanup = TRUE;
  21278. FlowControlSender = new (FlowControlSender) HTTP2FlowControlSender (TRUE, // IsServer
  21279. TRUE, // SendToRuntime
  21280. &RpcStatus
  21281. );
  21282. if (RpcStatus != RPC_S_OK)
  21283. {
  21284. FlowControlSender->HTTP2FlowControlSender::~HTTP2FlowControlSender();
  21285. goto AbortAndExit;
  21286. }
  21287. ChannelDataOriginator->SetUpperChannel(FlowControlSender);
  21288. FlowControlSender->SetLowerChannel(ChannelDataOriginator);
  21289. FlowControlSenderNeedsCleanup = TRUE;
  21290. PlugChannel = new (PlugChannel) HTTP2PlugChannel (&RpcStatus);
  21291. if (RpcStatus != RPC_S_OK)
  21292. {
  21293. PlugChannel->HTTP2PlugChannel::~HTTP2PlugChannel();
  21294. goto AbortAndExit;
  21295. }
  21296. FlowControlSender->SetUpperChannel(PlugChannel);
  21297. PlugChannel->SetLowerChannel(FlowControlSender);
  21298. PlugChannelNeedsCleanup = TRUE;
  21299. OutChannel = new (OutChannel) HTTP2ServerOutChannel (&RpcStatus);
  21300. if (RpcStatus != RPC_S_OK)
  21301. {
  21302. OutChannel->HTTP2ServerOutChannel::~HTTP2ServerOutChannel();
  21303. goto AbortAndExit;
  21304. }
  21305. RawChannel->SetTopChannel(OutChannel);
  21306. ChannelDataOriginator->SetTopChannel(OutChannel);
  21307. FlowControlSender->SetTopChannel(OutChannel);
  21308. PlugChannel->SetTopChannel(OutChannel);
  21309. PlugChannel->SetUpperChannel(OutChannel);
  21310. OutChannel->SetLowerChannel(PlugChannel);
  21311. ASSERT(RpcStatus == RPC_S_OK);
  21312. RawConnection->fAborted = 0;
  21313. *ReturnOutChannel = OutChannel;
  21314. *Connection = (WS_HTTP2_INITIAL_CONNECTION *)RawConnection;
  21315. goto CleanupAndExit;
  21316. AbortAndExit:
  21317. // We need to make sure that this failure path
  21318. // will not try freeing the raw connection.
  21319. // For this we set fIgnoreFree to true to ensure that
  21320. // the free will be ignored.
  21321. RawConnection->fIgnoreFree = TRUE;
  21322. if (PlugChannelNeedsCleanup)
  21323. {
  21324. PlugChannel->Abort(RpcStatus);
  21325. PlugChannel->FreeObject();
  21326. }
  21327. else if (FlowControlSenderNeedsCleanup)
  21328. {
  21329. FlowControlSender->Abort(RpcStatus);
  21330. FlowControlSender->FreeObject();
  21331. }
  21332. else if (ChannelDataOriginatorNeedsCleanup)
  21333. {
  21334. ChannelDataOriginator->Abort(RpcStatus);
  21335. ChannelDataOriginator->FreeObject();
  21336. }
  21337. else if (RawChannelNeedsCleanup)
  21338. {
  21339. RawChannel->Abort(RpcStatus);
  21340. RawChannel->FreeObject();
  21341. }
  21342. RawConnection->fIgnoreFree = FALSE;
  21343. // no need to clean up the raw connection.
  21344. // If we failed, the virtual connection
  21345. // is not created, and the caller will abort
  21346. // the original conneciton
  21347. if (MemoryBlock)
  21348. delete [] MemoryBlock;
  21349. CleanupAndExit:
  21350. return RpcStatus;
  21351. }
  21352. void HTTP2ServerVirtualConnection::TimeoutExpired (
  21353. IN TimerContext *pTimer
  21354. )
  21355. /*++
  21356. Routine Description:
  21357. A timeout expired before we cancelled the timer. Abort the connection.
  21358. Arguments:
  21359. pTimer - Pointer to the timer context for which the timeour has expired.
  21360. Return Value:
  21361. --*/
  21362. {
  21363. VerifyValidTimer(pTimer);
  21364. AbortChannels(RPC_P_TIMEOUT);
  21365. // Once we mark the timer as expired, we are no longer protected from
  21366. // the virtual connection being freed during the timer callback.
  21367. // We can't touch the virtual connection after this call.
  21368. TimerExpiredNotify(pTimer);
  21369. }
  21370. void HTTP2ServerVirtualConnection::DrainOutChannelPendingSends (
  21371. void
  21372. )
  21373. /*++
  21374. Routine Description:
  21375. Make sure all out channels have their sends drained.
  21376. Arguments:
  21377. Return Value:
  21378. --*/
  21379. {
  21380. int i;
  21381. HTTP2ServerOutChannel *OutChannel;
  21382. for (i = 0; i < 2; i ++)
  21383. {
  21384. OutChannel = (HTTP2ServerOutChannel *)OutChannels[i].LockChannelPointer();
  21385. if (OutChannel)
  21386. {
  21387. // make sure the pending sends are drained. Otherwise
  21388. // a send that is currently completing may violate
  21389. // rule 38
  21390. OutChannel->DrainPendingSends();
  21391. OutChannels[i].UnlockChannelPointer();
  21392. }
  21393. }
  21394. }