Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1371 lines
44 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. Protocol.cxx
  5. Abstract:
  6. Transport Protocol abstraction used mainly by PnP.
  7. The following is a brief description of the current RPC PnP mechanism:
  8. Whenever a non-local transport level object (a socket, or an address) is opened
  9. for a given protocol, it is added to the list of objects for the given protocol.
  10. This alllows all objects for a given protocol to be tracked down and closed if
  11. the protocol is unloaded. By the same token, objects closed are removed from
  12. the list of the given protocol.
  13. When a PnP notification arrives, the lower level transport code call into this PnP module
  14. to tell it that there may be a change of state. For each PnP protocol, the PnP code
  15. examines whether the protocol is active, and what was its last state. Depending of
  16. the outcome of this comparison, it will take appropriate action. Here's the finite
  17. state automaton with the transitions:
  18. Currently, RPC differentiates between four networking states of each protocol -
  19. protocol is not loaded, protocol is partially loaded (i.e. it is active, but
  20. does not have an address on it yet), it is fully loaded (or functional), and
  21. it is fully loaded and network address change monitoring is required. The
  22. fully loaded state with address change monitoring may be abbreviated to
  23. FunctionalMon for the purpose of this document.
  24. Note that Partially Loaded, and loaded without address are equivalent terms
  25. for the purpose of this module. Also, note that currently the networking
  26. code does not allow reloading of a protocol, so some of the code paths will
  27. never get exercised.
  28. RPC in turn maintains the following RPC (as opposed to networking) states:
  29. ProtocolNotLoaded
  30. ProtocolLoadedWithoutAddress
  31. ProtocolWasLoadedOrNeedsActivation
  32. ProtocolLoaded
  33. ProtocolWasLoadedOrNeedsActivationWithoutAddress
  34. ProtocolLoadedAndMonitored
  35. Depending on the last RPC state, and the new networking state, the following changes
  36. and state transitions are effected:
  37. If a PnP notification fails asynchronously, the completion port code will call into PnP
  38. code to try to resubmit the queries.
  39. Note that the threads on which overlapped WSAIoctl's are submitted are not protected.
  40. If a thread dies, the IO will fail, and the thread that picks the failure will resubmit
  41. the WSAIoctl. This strategy allows up to keep the thread pool smaller.
  42. Networking State Action
  43. RPC State
  44. ProtocolNotLoaded NotLoaded No-op
  45. PartiallyLoaded Submit a WSAIoctl to be notified
  46. when the protocol becomes
  47. functional.
  48. State = ProtocolLoadedWithoutAddress
  49. Functional State = ProtocolLoaded
  50. FunctionalMon Submit address change WSAIoctl.
  51. State = ProtocolLoadedAndMonitored
  52. ProtocolLoadedWithoutAddress NotLoaded Cancel WSAIoctl
  53. State = ProtocolNotLoaded
  54. PartiallyLoaded No-op
  55. Functional CancelWSAIoctl
  56. State = ProtocolLoaded
  57. FunctionalMon Submit address change WSAIoctl if necessary
  58. State = ProtocolLoadedAndMonitored
  59. ProtocolWasLoadedOrNeedsActivation NotLoaded No-op
  60. PartiallyLoaded Submit a WSAIoctl to be notified
  61. when the protocol becomes
  62. functional.
  63. State = ProtocolWasLoadedOrNeedsActivationWithoutAddress
  64. Functional Restart protocol
  65. State = ProtocolLoaded
  66. FunctionalMon Submit address change WSAIoctl.
  67. State = ProtocolLoadedAndMonitored
  68. ProtocolLoaded NotLoaded Unload protocol
  69. State = ProtocolWasLoadedOrNeedsActivation
  70. PartiallyLoaded Invalid
  71. Functional No-op
  72. FunctionalMon Invalid transition
  73. ProtocolWasLoadedOrNeedsActivationWithoutAddress
  74. NotLoaded Cancel WSAIoctl
  75. State = ProtocolWasLoadedOrNeedsActivation
  76. PartiallyLoaded No-op
  77. Functional Restart protocol
  78. State = ProtocolLoaded
  79. FunctionalMon Submit address change WSAIoctl.
  80. State = ProtocolLoadedAndMonitored
  81. ProtocolLoadedAndMonitored NotLoaded Cancel address change WSAIoctl
  82. Unload protocol
  83. State = ProtocolWasLoadedOrNeedsActivation
  84. PartiallyLoaded Resubmit address change WSAIoclt if necessary
  85. Functional Invalid transition
  86. FunctionalMon No-op
  87. ProtocolNeedToLoadWhenReady NotLoaded No-op
  88. PartiallyLoaded Submit a WSAIoctl to be notified
  89. when the protocol becomes
  90. functional.
  91. State = ProtocolNeedToLoadWhenReadyWithoutAddress
  92. Functional Restart protocol
  93. State = ProtocolLoaded
  94. FunctionalMon Submit address change WSAIoctl.
  95. State = ProtocolLoadedAndMonitored
  96. ProtocolNeedToLoadWhenReadyWithoutAddress
  97. NotLoaded Cancel WSAIoctl
  98. State = ProtocolNeedToLoadWhenReady
  99. PartiallyLoaded No-op
  100. Functional Restart protocol
  101. State = ProtocolLoaded
  102. FunctionalMon Submit address change WSAIoctl.
  103. State = ProtocolLoadedAndMonitored
  104. Author:
  105. Kamen Moutafov [KamenM]
  106. Revision History:
  107. KamenM 12/22/1998 Creation
  108. KamenM 03/05/1999 Adding state ProtocolLoadedAndMonitored and support for it.
  109. KamenM 07/17/2000 Adding support for ProtocolWasLoadedOrNeedsActivation/
  110. ProtocolWasLoadedOrNeedsActivationWithoutAddress
  111. --*/
  112. #include <precomp.hxx>
  113. #include <Protocol.hxx>
  114. void RPC_ENTRY NullAddressChangeFn( PVOID arg )
  115. {
  116. }
  117. RPC_ADDRESS_CHANGE_FN * AddressChangeFn = NullAddressChangeFn;
  118. #ifdef MAJOR_PNP_DEBUG
  119. const char *ProtocolStateNames[];
  120. #endif
  121. void TransportProtocol::DetectedAsFunctional(PROTOCOL_ID ProtocolId)
  122. {
  123. if (IsAddressChangeMonitoringOn(ProtocolId))
  124. {
  125. EnterCriticalSection(&AddressListLock);
  126. // monitor functional protocols for address change will
  127. // set the state
  128. MonitorFunctionalProtocolForAddressChange(ProtocolId);
  129. LeaveCriticalSection(&AddressListLock);
  130. }
  131. else
  132. {
  133. // we also need to take the critical section, and cancel any address change
  134. // notification (if any), to avoid race between a successful listen making
  135. // the protocol functional, and the address change notification completing
  136. EnterCriticalSection(&AddressListLock);
  137. CancelAddressChangeRequestIfNecessary(FALSE, ProtocolId);
  138. SetState(ProtocolLoaded, ProtocolId);
  139. LeaveCriticalSection(&AddressListLock);
  140. }
  141. }
  142. void TransportProtocol::HandleProtocolChange(IN WSAPROTOCOL_INFO *lpProtocolBuffer,
  143. IN int ProtocolCount,
  144. IN PROTOCOL_ID thisProtocolId)
  145. /*++
  146. Function Name: HandleProtocolChange
  147. Parameters:
  148. lpProtocolBuffer - an array of WSAPROTOCOL_INFO structures as returned by EnumProtocols
  149. ProtocolCount - the number of elements in the lpProtocolBuffer array
  150. thisProtocolId - the ID of the protocol for this object
  151. Description:
  152. This handles protocol state change for a particular protocol. The function is idempotent - it
  153. can be called many times safely, regardless of previous calls. It will turn into no-op if
  154. it is redundant.
  155. Returns:
  156. --*/
  157. {
  158. int i;
  159. BOOL fProtocolActive = FALSE;
  160. const WS_TRANS_INFO *pInfo;
  161. ASSERT(ProtocolCount >= 0);
  162. ASSERT(lpProtocolBuffer != NULL);
  163. ASSERT_TRANSPORT_PROTOCOL_STATE(thisProtocolId);
  164. if (
  165. #ifdef NETBIOS_ON
  166. (thisProtocolId == NBF) || (thisProtocolId == NBT) || (thisProtocolId == NBI) ||
  167. #endif
  168. #ifdef NCADG_MQ_ON
  169. (thisProtocolId == MSMQ) ||
  170. #endif
  171. (thisProtocolId == CDP)
  172. )
  173. return;
  174. if (IsTrailingProtocol(thisProtocolId))
  175. return;
  176. for (i = 0; i < ProtocolCount; i ++)
  177. {
  178. // if the enumerated protocol is the current protocol, break out of the loop
  179. if (MapProtocolId(lpProtocolBuffer[i].iProtocol, lpProtocolBuffer[i].iAddressFamily) == thisProtocolId)
  180. {
  181. fProtocolActive = TRUE;
  182. break;
  183. }
  184. }
  185. pInfo = &WsTransportTable[thisProtocolId];
  186. switch(State)
  187. {
  188. case ProtocolNotLoaded:
  189. case ProtocolLoadedWithoutAddress:
  190. // if the protocol was not loaded, but now it is active, attempt to verify
  191. // it is operational
  192. if (fProtocolActive)
  193. {
  194. #ifdef MAJOR_PNP_DEBUG
  195. if (State == ProtocolNotLoaded)
  196. {
  197. DbgPrint("Protocol %d was just loaded\n", thisProtocolId);
  198. }
  199. #endif
  200. // If the protocol is not fully functional, we will submit an address change
  201. // request to get notified when it does
  202. if (VerifyProtocolIsFunctional(thisProtocolId) == TRUE)
  203. {
  204. // we succeeded in changing the state of the protocol
  205. ASSERT((State == ProtocolLoaded) || (State == ProtocolLoadedAndMonitored));
  206. if (IsAddressChangeMonitoringOn(thisProtocolId))
  207. {
  208. MonitorFunctionalProtocolForAddressChange(thisProtocolId);
  209. (*AddressChangeFn)((PVOID) State);
  210. }
  211. }
  212. #ifdef MAJOR_PNP_DEBUG
  213. if (State == ProtocolLoadedWithoutAddress)
  214. {
  215. DbgPrint("Protocol %d was without an address\n", thisProtocolId);
  216. }
  217. #endif
  218. }
  219. else
  220. {
  221. if (State == ProtocolLoadedWithoutAddress)
  222. {
  223. // a protocol was removed without being fully initialized
  224. // cancel the pending query if any, and reset the state to not loaded
  225. CancelAddressChangeRequestIfNecessary(TRUE, thisProtocolId);
  226. SetState(ProtocolNotLoaded, thisProtocolId);
  227. #ifdef MAJOR_PNP_DEBUG
  228. DbgPrint("Protocol %d was removed without being fully initialized\n", thisProtocolId);
  229. #endif
  230. }
  231. // else - don't care. The protocol state is not loaded, and will remain so
  232. }
  233. break;
  234. case ProtocolWasLoadedOrNeedsActivation:
  235. case ProtocolWasLoadedOrNeedsActivationWithoutAddress:
  236. if (fProtocolActive)
  237. {
  238. // If the protocol is not fully functional, we will submit an address change
  239. // request to get notified when it does
  240. if (VerifyProtocolIsFunctional(thisProtocolId))
  241. {
  242. // if a protocol was loaded, and now is active, restart the addresses on it
  243. RestartProtocol(thisProtocolId);
  244. if (thisProtocolId == TCP)
  245. {
  246. GetTransportProtocol(HTTP)->RestartProtocol(HTTP);
  247. }
  248. // we succeeded in changing the state of the protocol
  249. ASSERT(State == ProtocolLoaded);
  250. if (IsAddressChangeMonitoringOn(thisProtocolId))
  251. {
  252. MonitorFunctionalProtocolForAddressChange(thisProtocolId);
  253. }
  254. }
  255. }
  256. else
  257. {
  258. // if the protocol was loaded, but it's not active, we don't care;
  259. // if it was trying to get an address, but then it was unloaded,
  260. // cancel the request
  261. if (State == ProtocolWasLoadedOrNeedsActivationWithoutAddress)
  262. {
  263. CancelAddressChangeRequestIfNecessary(TRUE, thisProtocolId);
  264. SetState(ProtocolWasLoadedOrNeedsActivation, thisProtocolId);
  265. #ifdef MAJOR_PNP_DEBUG
  266. DbgPrint("Protocol %d was removed without being fully initialized\n", thisProtocolId);
  267. #endif
  268. }
  269. }
  270. break;
  271. case ProtocolLoaded:
  272. ASSERT(IsAddressChangeMonitoringOn(thisProtocolId) == FALSE);
  273. // if the protocol was loaded, and it is active, we don't need to do anything;
  274. // if it was loaded, but is not active currently, we need to unload the protocol
  275. if (!fProtocolActive)
  276. {
  277. #ifdef MAJOR_PNP_DEBUG
  278. DbgPrint("Protocol %d was just unloaded\n", thisProtocolId);
  279. #endif
  280. UnloadProtocol(thisProtocolId);
  281. if (thisProtocolId == TCP)
  282. {
  283. GetTransportProtocol(HTTP)->UnloadProtocol(HTTP);
  284. }
  285. SetState(ProtocolWasLoadedOrNeedsActivation, thisProtocolId);
  286. }
  287. break;
  288. case ProtocolLoadedAndMonitored:
  289. ASSERT(IsAddressChangeMonitoringOn(thisProtocolId));
  290. // if it was loaded, but is not active currently, we need to unload the protocol
  291. if (!fProtocolActive)
  292. {
  293. #ifdef MAJOR_PNP_DEBUG
  294. DbgPrint("Protocol %d was just unloaded\n", thisProtocolId);
  295. #endif
  296. CancelAddressChangeRequestIfNecessary(TRUE, thisProtocolId);
  297. UnloadProtocol(thisProtocolId);
  298. if (thisProtocolId == TCP)
  299. {
  300. GetTransportProtocol(HTTP)->UnloadProtocol(HTTP);
  301. }
  302. SetState(ProtocolWasLoadedOrNeedsActivation, thisProtocolId);
  303. (*AddressChangeFn)((PVOID) State);
  304. }
  305. else
  306. {
  307. #ifdef MAJOR_PNP_DEBUG
  308. DbgPrint("Protocol %d is monitored and received event\n", thisProtocolId);
  309. #endif
  310. (*AddressChangeFn)((PVOID) State);
  311. }
  312. break;
  313. #if defined(DBG) || defined(_DEBUG)
  314. default:
  315. ASSERT(!"Invalid State");
  316. #endif
  317. }
  318. ASSERT_TRANSPORT_PROTOCOL_STATE(thisProtocolId);
  319. }
  320. void TransportProtocol::AddObjectToList(IN OUT BASE_ASYNC_OBJECT *pObj)
  321. /*++
  322. Function Name: AddObjectToList
  323. Parameters:
  324. pObj - the object to be added
  325. Description:
  326. Add the object to the list of transport objects for this protocol.
  327. Returns:
  328. --*/
  329. {
  330. EnterCriticalSection(&AddressListLock);
  331. RpcpfInsertHeadList(&ObjectList, &pObj->ObjectList);
  332. LeaveCriticalSection(&AddressListLock);
  333. }
  334. void TransportProtocol::RemoveObjectFromList(IN OUT BASE_ASYNC_OBJECT *pObj)
  335. /*++
  336. Function Name: RemoveObjectFromList
  337. Parameters:
  338. pObj - the object to be removed
  339. Description:
  340. Removes the object from the list of transport objects for this protocol.
  341. Returns:
  342. --*/
  343. {
  344. BASE_ASYNC_OBJECT *Prev, *Cur;
  345. Prev = NULL;
  346. EnterCriticalSection(&AddressListLock);
  347. RpcpfRemoveEntryList(&pObj->ObjectList);
  348. LeaveCriticalSection(&AddressListLock);
  349. }
  350. BOOL TransportProtocol::ResubmitQueriesIfNecessary(PROTOCOL_ID ProtocolId)
  351. /*++
  352. Function Name: ResubmitQueriesIfNecessary
  353. Parameters:
  354. ProtocolId - the ID of the current protocol
  355. Description:
  356. If there was a WSAIoctl pending that failed, it will be resubmitted.
  357. If this protocol was being monitored, try to restart monitoring if necessary
  358. Returns:
  359. FALSE if the WSAIoctl was not resubmitted successfully.
  360. TRUE if the WSAIoctl was resubmitted successfully, or there was no need to resubmit it.
  361. --*/
  362. {
  363. if (addressChangeSocket)
  364. {
  365. if ((addressChangeOverlapped.Internal != 0) && (addressChangeOverlapped.Internal != STATUS_PENDING))
  366. {
  367. if (SubmitAddressChangeQuery() == FALSE)
  368. return FALSE;
  369. }
  370. }
  371. if (State == ProtocolLoadedAndMonitored)
  372. {
  373. if (MonitorFunctionalProtocolForAddressChange(ProtocolId) == FALSE)
  374. return FALSE;
  375. }
  376. return TRUE;
  377. }
  378. PROTOCOL_ID
  379. MapProtocolId (
  380. IN UINT ProtocolId,
  381. IN UINT AddressFamily
  382. )
  383. /*++
  384. Function Name: MapProtocolId
  385. Parameters:
  386. ProtocolId - Winsock protocol ID
  387. AddressFamily - Winsock address family
  388. Description:
  389. Converts a Winsock Protocol ID to a RPC Transport protocol ID.
  390. Returns:
  391. The RPC Transport Protocol ID if successfull, or -1 if no mapping can be found
  392. --*/
  393. {
  394. unsigned id;
  395. for (id = 1; id < cWsTransportTable; id++)
  396. {
  397. if ((WsTransportTable[id].Protocol == (int) ProtocolId)
  398. && (WsTransportTable[id].AddressFamily == (int) AddressFamily))
  399. {
  400. return id;
  401. }
  402. }
  403. return -1;
  404. }
  405. BOOL TransportProtocol::HandlePnPStateChange(void)
  406. /*++
  407. Function Name: HandlePnPNotification
  408. Parameters:
  409. Description:
  410. Whenever a PnP notification (NewAddress) arrives, the completion port will direct it
  411. to this routine, which will handle all state management and all handling of the PnP
  412. notification.
  413. Returns:
  414. TRUE if the runtime should be notified that a protocol state change has occurred.
  415. FALSE if the run time should not be notified, or need not be notified that a
  416. protocol state change has occurred.
  417. --*/
  418. {
  419. int i;
  420. //
  421. // Enumerate the currently loaded protocols
  422. //
  423. WSAPROTOCOL_INFO *lpProtocolBuffer;
  424. DWORD dwBufferLength = 512;
  425. int ProtocolCount;
  426. PROTOCOL_ID ProtocolId;
  427. TransportProtocol *pCurrentProtocol;
  428. BOOL fRetVal;
  429. EnterCriticalSection(&AddressListLock);
  430. ASSERT(hWinsock2);
  431. while (1)
  432. {
  433. lpProtocolBuffer = (WSAPROTOCOL_INFO *) I_RpcAllocate(dwBufferLength);
  434. if (lpProtocolBuffer == 0)
  435. {
  436. fRetVal = FALSE;
  437. goto CleanupAndReturn;
  438. }
  439. ProtocolCount = WSAEnumProtocolsT(
  440. 0,
  441. lpProtocolBuffer,
  442. &dwBufferLength
  443. );
  444. if (ProtocolCount != SOCKET_ERROR)
  445. {
  446. break;
  447. }
  448. I_RpcFree(lpProtocolBuffer);
  449. if (GetLastError() != WSAENOBUFS)
  450. {
  451. fRetVal = FALSE;
  452. goto CleanupAndReturn;
  453. }
  454. }
  455. for (i = 1; i < MAX_PROTOCOLS; i++)
  456. {
  457. pCurrentProtocol = GetTransportProtocol(i);
  458. pCurrentProtocol->HandleProtocolChange(lpProtocolBuffer, ProtocolCount, i);
  459. }
  460. I_RpcFree(lpProtocolBuffer);
  461. fRetVal = g_NotifyRt;
  462. CleanupAndReturn:
  463. LeaveCriticalSection(&AddressListLock);
  464. #ifdef MAJOR_PNP_DEBUG
  465. DumpProtocolState();
  466. #endif
  467. return fRetVal;
  468. }
  469. BOOL TransportProtocol::ResubmitQueriesIfNecessary(void)
  470. /*++
  471. Function Name: ResubmitQueriesIfNecessary
  472. Parameters:
  473. Description:
  474. Iterates through all protocols and calls their ResubmitQueriesIfNecessary
  475. Returns:
  476. FALSE if at least one protocol needed to resubmit a query, but failed to do so
  477. TRUE otherwise
  478. --*/
  479. {
  480. int i;
  481. BOOL fAllResubmitsSucceeded = TRUE;
  482. TransportProtocol *pCurrentProtocol;
  483. #ifdef MAJOR_PNP_DEBUG
  484. DbgPrint("Resubmitting queries for process %d\n", GetCurrentProcessId());
  485. #endif
  486. EnterCriticalSection(&AddressListLock);
  487. for (i = 1; i < MAX_PROTOCOLS; i++)
  488. {
  489. pCurrentProtocol = GetTransportProtocol(i);
  490. if (!pCurrentProtocol->ResubmitQueriesIfNecessary(i))
  491. fAllResubmitsSucceeded = FALSE;
  492. }
  493. LeaveCriticalSection(&AddressListLock);
  494. return fAllResubmitsSucceeded;
  495. }
  496. void TransportProtocol::AddObjectToProtocolList(BASE_ASYNC_OBJECT *pObj)
  497. {
  498. GetTransportProtocol(pObj->id)->AddObjectToList(pObj);
  499. }
  500. void TransportProtocol::RemoveObjectFromProtocolList(IN OUT BASE_ASYNC_OBJECT *pObj)
  501. {
  502. // in some cases, we can legally have the id set to INVALID_PROTOCOL_ID
  503. // this happens when we have initialized the connection, but have failed
  504. // before calling Open on it, and then we attempt to destroy it
  505. if (pObj->id != INVALID_PROTOCOL_ID)
  506. {
  507. GetTransportProtocol(pObj->id)->RemoveObjectFromList(pObj);
  508. }
  509. }
  510. BOOL TransportProtocol::VerifyProtocolIsFunctional(IN PROTOCOL_ID ProtocolId)
  511. /*++
  512. Function Name: VerifyProtocolIsFunctional
  513. Parameters: ProtocolId - the protocol which we're attempting to verify as functional or not
  514. Description: Tries to find out the listening address for a loaded protocol. The address
  515. itself is not used anywhere. It just testifies that the protocol is fully operational.
  516. Depending on how far it gets with testing whether the protocol is operational,
  517. it will change the State to ProtocolLoaded, ProtocolLoadedWithoutAddress or
  518. ProtocolWasLoadedOrNeedsActivationWithoutAddress. It will return TRUE iff the state is moved to
  519. ProtocolLoaded.
  520. Returns: TRUE if the address was found and the protocol was fully operational
  521. FALSE if the address could not be found, and the protocol is not
  522. fully operational. Note that there are two subcases here. One is when
  523. the protocol is not operational (or we cannot confirm that for lack of
  524. resources for example) and it has no sign of becoming operational. The
  525. second is when the protocol is not operational, but there are chances of
  526. it becoming operational. This happens with protocols that take some
  527. time to initialize. In the second case, this function will arrange for
  528. a retry attempt by posting an async WSAIoctl request to the completion
  529. port. In the current code base, we don't differentiate between the two
  530. cases because we don't need to. We may need to do so in the future.
  531. --*/
  532. {
  533. ASSERT((State == ProtocolNotLoaded)
  534. || (State == ProtocolWasLoadedOrNeedsActivation)
  535. || (State == ProtocolLoadedWithoutAddress)
  536. || (State == ProtocolWasLoadedOrNeedsActivationWithoutAddress));
  537. ASSERT_TRANSPORT_PROTOCOL_STATE(ProtocolId);
  538. if (OpenAddressChangeRequestSocket(ProtocolId) == FALSE)
  539. goto AbortAndCleanup;
  540. // if the socket already has an address, skip further checks
  541. // NOTE: this check provides a fast way to check initialization state of
  542. // protocols that initialize quickly, but more importantly, it provides a
  543. // handling path for protocols that have submitted an address list change query
  544. // and now are getting back the result
  545. if (DoesAddressSocketHaveAddress())
  546. {
  547. #ifdef MAJOR_PNP_DEBUG
  548. DbgPrint("Protocol %d is functional (1)\n", ProtocolId);
  549. #endif
  550. CancelAddressChangeRequestIfNecessary(FALSE, ProtocolId);
  551. SetStateToLoadedAndMonitorProtocolIfNecessary(ProtocolId);
  552. ASSERT_TRANSPORT_PROTOCOL_STATE(ProtocolId);
  553. return TRUE;
  554. }
  555. // if there isn't a pending request, and there isn't a successful request (i.e. there is either
  556. // a failed request, or no request has been submitted so far)
  557. if ((addressChangeOverlapped.Internal != 0) && (addressChangeOverlapped.Internal != STATUS_PENDING))
  558. {
  559. #ifdef MAJOR_PNP_DEBUG
  560. DbgPrint("Submitting WSAIoclt for protocol %d\n", ProtocolId);
  561. #endif
  562. if (!SubmitAddressChangeQuery())
  563. goto AbortAndCleanup;
  564. }
  565. // check once more whether we have address - this takes care of the race where the
  566. // address did arrive between the time we checked for it in the beginning of this
  567. // function and the time we submitted the address change query
  568. if (DoesAddressSocketHaveAddress())
  569. {
  570. #ifdef MAJOR_PNP_DEBUG
  571. DbgPrint("Protocol %d is functional (2)\n", ProtocolId);
  572. #endif
  573. CancelAddressChangeRequestIfNecessary(FALSE, ProtocolId);
  574. SetStateToLoadedAndMonitorProtocolIfNecessary(ProtocolId);
  575. ASSERT_TRANSPORT_PROTOCOL_STATE(ProtocolId);
  576. return TRUE;
  577. }
  578. // regardless of whether we succeeded immediately or we are pending, advance the
  579. // state to ProtocolLoadedWithoutAddress and return not loaded. The completion at the
  580. // completion port will take care of the rest
  581. if (State == ProtocolWasLoadedOrNeedsActivation)
  582. SetState(ProtocolWasLoadedOrNeedsActivationWithoutAddress, ProtocolId);
  583. else if (State == ProtocolNotLoaded)
  584. SetState(ProtocolLoadedWithoutAddress, ProtocolId);
  585. #ifdef MAJOR_PNP_DEBUG
  586. else
  587. {
  588. DbgPrint("VerifyProtocolIsFunctional did not change state for protocol %d, state: %s\n", ProtocolId,
  589. ProtocolStateNames[State]);
  590. }
  591. #endif
  592. ASSERT_TRANSPORT_PROTOCOL_STATE(ProtocolId);
  593. return FALSE;
  594. AbortAndCleanup:
  595. // TRUE or FALSE for this argument doesn't matter here -
  596. // the operation has failed
  597. CancelAddressChangeRequestIfNecessary(FALSE, ProtocolId);
  598. ASSERT_TRANSPORT_PROTOCOL_STATE(ProtocolId);
  599. return FALSE;
  600. }
  601. BOOL TransportProtocol::DoesAddressSocketHaveAddress(void)
  602. /*++
  603. Function Name: DoesAddressSocketHaveAddress
  604. Parameters:
  605. Description:
  606. Checks if a valid address can be obtained for this protocol.
  607. Returns:
  608. TRUE - a valid address could be obtained for this protocol
  609. FALSE - otherwise
  610. --*/
  611. {
  612. DWORD byteRet = 0;
  613. char buf[40];
  614. ASSERT(addressChangeSocket != 0);
  615. if (WSAIoctl(addressChangeSocket, SIO_ADDRESS_LIST_QUERY,
  616. 0, 0, buf, sizeof(buf), &byteRet, NULL, NULL) == SOCKET_ERROR)
  617. {
  618. return FALSE;
  619. }
  620. // if the result has non-zero length ...
  621. if (byteRet != 0)
  622. {
  623. #if 0
  624. int i;
  625. DbgPrint("WSAIoctl returned:\n");
  626. for (i = 0; i < byteRet; i ++)
  627. {
  628. DbgPrint(" %X", (unsigned long) buf[i]);
  629. }
  630. DbgPrint("\nWSAIoctl with ADDRESS_LIST_QUERY returned addresses success\n");
  631. #endif
  632. // ... and the resulting value is non zero ...
  633. if (*(long *)buf != 0)
  634. {
  635. // ... we have managed to get the true address
  636. return TRUE;
  637. }
  638. }
  639. return FALSE;
  640. }
  641. void TransportProtocol::CancelAddressChangeRequestIfNecessary(BOOL fForceCancel, IN PROTOCOL_ID ProtocolId)
  642. /*++
  643. Function Name: CancelAddressChangeRequestIfNecessary
  644. Parameters:
  645. Description:
  646. If there's an active WSAIoctl on the protocol, cancel it by closing the socket.
  647. Returns:
  648. --*/
  649. {
  650. if (addressChangeSocket != 0)
  651. {
  652. // if the address change monitoring is off, or cancel is
  653. // forced, do the actual cancelling. That is, we don't
  654. // cancel if this is a monitored protocol and cancel is
  655. // optional
  656. if (!IsAddressChangeMonitoringOn(ProtocolId) || fForceCancel)
  657. {
  658. #ifdef MAJOR_PNP_DEBUG
  659. DbgPrint("Address change request cancelled\n");
  660. #endif
  661. closesocket(addressChangeSocket);
  662. addressChangeSocket = 0;
  663. addressChangeOverlapped.Internal = -1;
  664. }
  665. }
  666. }
  667. void TransportProtocol::RestartProtocol(PROTOCOL_ID ProtocolId)
  668. /*++
  669. Function Name: RestartProtocol
  670. Parameters:
  671. ProtocolId - the protocol to be restarted.
  672. Description:
  673. Restarts all addresses on this protocol.
  674. Returns:
  675. --*/
  676. {
  677. BASE_ASYNC_OBJECT *Obj;
  678. BOOL fAddressFound = 0;
  679. RPC_STATUS Status;
  680. LIST_ENTRY *CurrentEntry;
  681. VALIDATE(ProtocolId)
  682. {
  683. TCP,
  684. #ifdef SPX_ON
  685. SPX,
  686. #endif
  687. #ifdef APPLETALK_ON
  688. DSP,
  689. #endif
  690. HTTP,
  691. UDP,
  692. #ifdef IPX_ON
  693. IPX,
  694. #endif
  695. TCP_IPv6
  696. } END_VALIDATE;
  697. CurrentEntry = ObjectList.Flink;
  698. while(CurrentEntry != &ObjectList)
  699. {
  700. Obj = CONTAINING_RECORD(CurrentEntry, BASE_ASYNC_OBJECT, ObjectList);
  701. ASSERT(Obj->id == (int) ProtocolId);
  702. if (Obj->type & ADDRESS)
  703. {
  704. if (Obj->type & DATAGRAM)
  705. {
  706. Status = DG_ReactivateAddress((WS_DATAGRAM_ENDPOINT *) Obj);
  707. }
  708. else
  709. {
  710. Status = WS_ReactivateAddress((WS_ADDRESS *) Obj);
  711. }
  712. if (Status == RPC_S_OK)
  713. {
  714. fAddressFound = 1;
  715. COMMON_AddressManager((BASE_ADDRESS *) Obj);
  716. }
  717. }
  718. CurrentEntry = CurrentEntry->Flink;
  719. }
  720. if (fAddressFound)
  721. {
  722. COMMON_PostNonIoEvent(TRANSPORT, 0, 0);
  723. }
  724. }
  725. void TransportProtocol::UnloadProtocol(PROTOCOL_ID ProtocolId)
  726. /*++
  727. Function Name: UnloadProtocol
  728. Parameters:
  729. ProtocolId - the protocol to be unloaded.
  730. Description:
  731. Walks the list of the protocol transport objects. Closes the connections, and removes the
  732. addresses from the list. Thus failing requests on addresses will not be retried.
  733. Returns:
  734. --*/
  735. {
  736. BASE_ASYNC_OBJECT *Obj;
  737. LIST_ENTRY *CurrentEntry;
  738. VALIDATE(ProtocolId)
  739. {
  740. TCP,
  741. #ifdef SPX_ON
  742. SPX,
  743. #endif
  744. #ifdef APPLETALK_ON
  745. DSP,
  746. #endif
  747. HTTP,
  748. UDP,
  749. #ifdef IPX_ON
  750. IPX,
  751. #endif
  752. TCP_IPv6,
  753. HTTPv2
  754. } END_VALIDATE;
  755. CurrentEntry = ObjectList.Flink;
  756. //
  757. // - Cleanup all the objects (ie: close the socket).
  758. // - Remove all objects other than address objects
  759. // from the list.
  760. //
  761. while(CurrentEntry != &ObjectList)
  762. {
  763. Obj = CONTAINING_RECORD(CurrentEntry, BASE_ASYNC_OBJECT, ObjectList);
  764. ASSERT(Obj->id == (int)ProtocolId);
  765. if (Obj->type & ADDRESS)
  766. {
  767. COMMON_RemoveAddress((BASE_ADDRESS *) Obj);
  768. }
  769. else
  770. {
  771. RpcpfRemoveEntryList(&Obj->ObjectList);
  772. if (ProtocolId != HTTPv2)
  773. WS_Abort(Obj);
  774. else
  775. HTTP_Abort(Obj);
  776. }
  777. CurrentEntry = CurrentEntry->Flink;
  778. }
  779. }
  780. BOOL TransportProtocol::SubmitAddressChangeQuery(void)
  781. /*++
  782. Function Name: SubmitAddressChangeQuery
  783. Parameters:
  784. Description:
  785. Submits an address change query (WSAIoctl)
  786. Returns:
  787. TRUE if the WSAIoctl was successfully posted.
  788. FALSE otherwise
  789. --*/
  790. {
  791. ASSERT(addressChangeSocket != 0);
  792. static DWORD dwBytesReturned;
  793. //
  794. // Post an address list change request
  795. //
  796. addressChangeOverlapped.hEvent = 0;
  797. addressChangeOverlapped.Offset = 0;
  798. addressChangeOverlapped.OffsetHigh = 0;
  799. addressChangeOverlapped.Internal = 0;
  800. // submit the address change request - it will always complete on the completion port
  801. // we don't care about the dwBytesReturned. The provider requires a valid address, or
  802. // it rejects the request
  803. if (WSAIoctl(addressChangeSocket, SIO_ADDRESS_LIST_CHANGE,
  804. 0, 0, 0, 0, &dwBytesReturned, &addressChangeOverlapped, 0) == SOCKET_ERROR)
  805. {
  806. if (WSAGetLastError() != ERROR_IO_PENDING)
  807. {
  808. #ifdef MAJOR_PNP_DEBUG
  809. DbgPrint("Submitting WSAIoclt failed with: %d\n", GetLastError());
  810. #endif
  811. return FALSE;
  812. }
  813. }
  814. return TRUE;
  815. }
  816. void TransportProtocol::SetState(TransportProtocolStates newState, PROTOCOL_ID ProtocolId)
  817. /*++
  818. Function Name: SetState
  819. Parameters:
  820. newState - the new state that the protocol needs to move to
  821. ProtocolId - the protocol number of this protocol
  822. Description:
  823. Sets the state of the protocol. Nobody should write the state directly, because
  824. protocol state mirroring will stop working.
  825. Returns:
  826. --*/
  827. {
  828. TransportProtocol *CurrentProtocol;
  829. #ifdef MAJOR_PNP_DEBUG
  830. DbgPrint("Protocol %d moved from state: %s to state: %s\n", ProtocolId, ProtocolStateNames[State],
  831. ProtocolStateNames[newState]);
  832. #endif
  833. // either the address change monitoring is not on for this protocol, or
  834. // the protocol doesn't move to loaded state, but not both
  835. ASSERT(!IsAddressChangeMonitoringOn(ProtocolId) || (newState != ProtocolLoaded));
  836. State = newState;
  837. if (ProtocolId == TCP)
  838. {
  839. // if a base protocols is moved into loaded and monitored, make sure
  840. // the trailing protocols doesn't follow it there. In such a case
  841. // the trailing protocol becomes only loaded
  842. if (newState == ProtocolLoadedAndMonitored)
  843. {
  844. GetTransportProtocol(HTTP)->State = ProtocolLoaded;
  845. }
  846. else
  847. {
  848. GetTransportProtocol(HTTP)->State = newState;
  849. }
  850. MirrorProtocolState(TCP_IPv6);
  851. }
  852. else if (ProtocolId == TCP_IPv6)
  853. {
  854. MirrorProtocolState(TCP);
  855. }
  856. }
  857. void TransportProtocol::SetStateToLoadedAndMonitorProtocolIfNecessary(PROTOCOL_ID ProtocolId)
  858. {
  859. if (IsAddressChangeMonitoringOn(ProtocolId))
  860. {
  861. // monitor functional protocols for address change will
  862. // set the state
  863. MonitorFunctionalProtocolForAddressChange(ProtocolId);
  864. }
  865. else
  866. SetState(ProtocolLoaded, ProtocolId);
  867. }
  868. RPC_STATUS InitTransportProtocols(void)
  869. /*++
  870. Function Name: InitTransportProtocols
  871. Parameters:
  872. Description:
  873. Initializes all transport level protocols. This function should be called before
  874. any of the TransportProtocol functions.
  875. Returns:
  876. --*/
  877. {
  878. TransportProtocolArray = new TransportProtocol[MAX_PROTOCOLS];
  879. if (TransportProtocolArray == NULL)
  880. return (RPC_S_OUT_OF_MEMORY);
  881. else
  882. return RPC_S_OK;
  883. }
  884. #if defined(DBG) || defined(_DEBUG)
  885. void TransportProtocol::AssertTransportProtocolState(void)
  886. /*++
  887. Function Name: AssertTransportProtocolState
  888. Parameters:
  889. Description:
  890. Loops through all protocols and calls AssertState on them
  891. Returns:
  892. --*/
  893. {
  894. int i;
  895. for (i = 1; i < MAX_PROTOCOLS; i ++)
  896. {
  897. GetTransportProtocol(i)->AssertState(i);
  898. }
  899. }
  900. void TransportProtocol::AssertState(PROTOCOL_ID ProtocolId)
  901. /*++
  902. Function Name: AssertState
  903. Parameters:
  904. ProtocolId - the protocol number of the this protocol
  905. Description:
  906. Currently this includes that addressChangeSocket is set only in the *WithoutAddress states
  907. and that all the objects in this protocol list are of the same protocol as this protocol.
  908. Returns:
  909. --*/
  910. {
  911. BASE_ASYNC_OBJECT *pObject;
  912. LIST_ENTRY *CurrentEntry;
  913. // make sure that the internal state of the object is consistent
  914. ASSERT (State >= ProtocolNotLoaded);
  915. ASSERT (State <= ProtocolLoadedAndMonitored);
  916. if (IsTrailingProtocol(ProtocolId))
  917. {
  918. ASSERT(addressChangeSocket == 0);
  919. }
  920. else
  921. {
  922. // if we are in one of these states, there should be no address change request pending
  923. if ((State == ProtocolNotLoaded)
  924. || (State == ProtocolWasLoadedOrNeedsActivation)
  925. || (State == ProtocolLoaded))
  926. {
  927. ASSERT(addressChangeSocket == 0);
  928. }
  929. else
  930. {
  931. // if we are in one of the else states, there must be address change request pending
  932. ASSERT(addressChangeSocket != 0);
  933. }
  934. }
  935. // walk the object list and make sure every object is of the same protocol
  936. CurrentEntry = ObjectList.Flink;
  937. while (CurrentEntry != &ObjectList)
  938. {
  939. pObject = CONTAINING_RECORD(CurrentEntry, BASE_ASYNC_OBJECT, ObjectList);
  940. ASSERT(pObject->id == ProtocolId);
  941. CurrentEntry = CurrentEntry->Flink;
  942. }
  943. }
  944. #endif
  945. BOOL TransportProtocol::MonitorFunctionalProtocolForAddressChange(PROTOCOL_ID ProtocolId)
  946. /*++
  947. Function Name: MonitorFunctionalProtocolForAddressChange
  948. Parameters:
  949. ProtocolId - the protocol id of the current protocol
  950. Description:
  951. Makes sure that an already functional protocol is monitored for address change. This is done
  952. by:
  953. - if an address change socket does not exist, one is opened.
  954. - if no address change WSAIoctl is pending on the socket, one is posted.
  955. Returns:
  956. TRUE if the posting of address change was successful
  957. FALSE if it wasn't
  958. --*/
  959. {
  960. BOOL bRetVal = FALSE;
  961. // OpenAddressChangeRequestSocket will take care to check whether there's already
  962. // a socket opened
  963. if (OpenAddressChangeRequestSocket(ProtocolId) == FALSE)
  964. goto Cleanup;
  965. if (addressChangeOverlapped.Internal != STATUS_PENDING)
  966. {
  967. if (SubmitAddressChangeQuery() == FALSE)
  968. goto Cleanup;
  969. }
  970. bRetVal = TRUE;
  971. Cleanup:
  972. if (State != ProtocolLoadedAndMonitored)
  973. SetState(ProtocolLoadedAndMonitored, ProtocolId);
  974. return bRetVal;
  975. }
  976. BOOL TransportProtocol::OpenAddressChangeRequestSocket(PROTOCOL_ID ProtocolId)
  977. /*++
  978. Function Name: OpenAddressChangeRequestSocket
  979. Parameters:
  980. ProtocolId - the protocol id of the current protocol
  981. Description:
  982. Makes sure that an address change request socket is opened.
  983. Returns:
  984. TRUE if the opening was successful
  985. FALSE if it wasn't
  986. --*/
  987. {
  988. const WS_TRANS_INFO *pInfo = &WsTransportTable[ProtocolId];
  989. HANDLE h;
  990. // we may end up with non-zero addressChangeSocket if this is an address change query
  991. // request coming back to us. In this case we don't need to open up another socket
  992. if (addressChangeSocket == 0)
  993. {
  994. ASSERT((State == ProtocolNotLoaded)
  995. || (State == ProtocolWasLoadedOrNeedsActivation)
  996. || (State == ProtocolLoaded));
  997. //
  998. // Create a socket
  999. //
  1000. addressChangeSocket = WSASocketT(pInfo->AddressFamily,
  1001. pInfo->SocketType,
  1002. pInfo->Protocol,
  1003. 0,
  1004. 0,
  1005. WSA_FLAG_OVERLAPPED);
  1006. if (addressChangeSocket == INVALID_SOCKET)
  1007. {
  1008. //
  1009. // We should be able to at least open a socket on the protocol,
  1010. // if not we got a bogus notification or we're out of resources
  1011. addressChangeSocket = 0;
  1012. return FALSE;
  1013. }
  1014. //
  1015. // make the handle non-inheritable so it goes away when we close it.
  1016. //
  1017. if (FALSE == SetHandleInformation( (HANDLE) addressChangeSocket, HANDLE_FLAG_INHERIT, 0))
  1018. {
  1019. closesocket(addressChangeSocket);
  1020. addressChangeSocket = 0;
  1021. return FALSE;
  1022. }
  1023. // associate the socket with the completion port so that we get the notification there
  1024. h = CreateIoCompletionPort((HANDLE)addressChangeSocket,
  1025. RpcCompletionPort,
  1026. NewAddress,
  1027. 0);
  1028. if (h == 0)
  1029. {
  1030. closesocket(addressChangeSocket);
  1031. addressChangeSocket = 0;
  1032. return FALSE;
  1033. }
  1034. else
  1035. {
  1036. ASSERT(h == RpcCompletionPort);
  1037. }
  1038. }
  1039. else
  1040. {
  1041. // we may have a protocol in state ProtocolNotLoaded, because we are just trying
  1042. // to bring it to loaded state
  1043. ASSERT((State == ProtocolLoadedWithoutAddress)
  1044. || (State == ProtocolWasLoadedOrNeedsActivationWithoutAddress)
  1045. || (State == ProtocolLoadedAndMonitored) || (State == ProtocolNotLoaded));
  1046. }
  1047. #ifdef MAJOR_PNP_DEBUG
  1048. DbgPrint("Socket was successfully opened for protocol %d\n", ProtocolId);
  1049. #endif
  1050. return TRUE;
  1051. }
  1052. void
  1053. TransportProtocol::MirrorProtocolState (
  1054. IN PROTOCOL_ID MirrorProtocolId
  1055. )
  1056. /*++
  1057. Function Name: MirrorProtocolState
  1058. Parameters:
  1059. MirrorProtocolId - the protocol which is mirrored
  1060. Description:
  1061. If this is one of the protocols in a dual stack configuration, change
  1062. the other protocol into appropriate state
  1063. Returns:
  1064. --*/
  1065. {
  1066. TransportProtocol *MirrorProtocol;
  1067. MirrorProtocol = GetTransportProtocol(MirrorProtocolId);
  1068. if ((State == ProtocolLoadedAndMonitored) || (State == ProtocolLoaded))
  1069. {
  1070. if (MirrorProtocol->State == ProtocolNotLoaded)
  1071. {
  1072. MirrorProtocol->SetState(ProtocolWasLoadedOrNeedsActivation, MirrorProtocolId);
  1073. }
  1074. else if (MirrorProtocol->State == ProtocolLoadedWithoutAddress)
  1075. {
  1076. MirrorProtocol->SetState(ProtocolWasLoadedOrNeedsActivationWithoutAddress, MirrorProtocolId);
  1077. }
  1078. }
  1079. }
  1080. #ifdef MAJOR_PNP_DEBUG
  1081. void TransportProtocol::DumpProtocolState(void)
  1082. /*++
  1083. Function Name: DumpProtocolState
  1084. Parameters:
  1085. Description:
  1086. Iterates through all protocol and calls their DumpProtocolState
  1087. Returns:
  1088. --*/
  1089. {
  1090. int i;
  1091. DbgPrint("Dumping protocol state for process %d\n", GetCurrentProcessId());
  1092. for (i = 1; i < MAX_PROTOCOLS; i ++)
  1093. {
  1094. GetTransportProtocol(i)->DumpProtocolState(i);
  1095. }
  1096. }
  1097. const char *ProtocolStateNames[] = {"ProtocolNotLoaded", "ProtocolLoadedWithoutAddress" ,
  1098. "ProtocolWasLoadedOrNeedsActivation", "ProtocolLoaded",
  1099. "ProtocolWasLoadedOrNeedsActivationWithoutAddress",
  1100. "ProtocolLoadedAndMonitored"};
  1101. void TransportProtocol::DumpProtocolState(PROTOCOL_ID ProtocolId)
  1102. /*++
  1103. Function Name: DumpProtocolState
  1104. Parameters:
  1105. ProtocolId - the protocol number for this protocol.
  1106. Description:
  1107. Dumps all significant information for this protcool on the debugger
  1108. Returns:
  1109. --*/
  1110. {
  1111. BASE_ASYNC_OBJECT *pCurrentObject;
  1112. LIST_ENTRY *pCurrentEntry = ObjectList.Flink;
  1113. int fFirstTime = TRUE;
  1114. const RPC_CHAR *Protseq;
  1115. if (TransportTable[ProtocolId].pInfo)
  1116. Protseq = TransportTable[ProtocolId].pInfo->ProtocolSequence;
  1117. else
  1118. Protseq = L"(null)";
  1119. DbgPrint("Protocol: %S\n", Protseq);
  1120. DbgPrint("State: %s, Addr Change Socket: %X, Addr Change Overlapped: %X\n",
  1121. ProtocolStateNames[State], addressChangeSocket, (ULONG_PTR)&addressChangeOverlapped);
  1122. while (pCurrentEntry != &ObjectList)
  1123. {
  1124. if (fFirstTime)
  1125. {
  1126. DbgPrint("Object List:\n");
  1127. fFirstTime = FALSE;
  1128. }
  1129. pCurrentObject = CONTAINING_RECORD(pCurrentEntry, BASE_ASYNC_OBJECT, ObjectList);
  1130. DbgPrint("\t%X\n", (ULONG_PTR)pCurrentObject);
  1131. pCurrentEntry = pCurrentEntry->Flink;
  1132. }
  1133. }
  1134. #endif
  1135. TransportProtocol *TransportProtocolArray;