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.

396 lines
11 KiB

  1. //
  2. // Module : arcmgr.cpp
  3. //
  4. // Class : CArcMgr
  5. //
  6. // Purpose: AutoReconnection mananger class - drives policy for
  7. // ts client autoreconnection
  8. //
  9. // Copyright(C) Microsoft Corporation 2001
  10. //
  11. // Author : Nadim Abdo (nadima)
  12. //
  13. #include "stdafx.h"
  14. #include "atlwarn.h"
  15. BEGIN_EXTERN_C
  16. #define TRC_GROUP TRC_GROUP_UI
  17. #define TRC_FILE "arcmgr"
  18. #include <atrcapi.h>
  19. END_EXTERN_C
  20. //Header generated from IDL
  21. #include "mstsax.h"
  22. #include "mstscax.h"
  23. #include "arcmgr.h"
  24. #include "tscerrs.h"
  25. //
  26. // Total time to wait between ARC attempts
  27. //
  28. #define ARC_RECONNECTION_DELAY (3000)
  29. CArcMgr::CArcMgr() :
  30. _pMsTscAx(NULL),
  31. _nArcAttempts(0),
  32. _fAutomaticArc(TRUE),
  33. _fContinueArc(FALSE)
  34. {
  35. DC_BEGIN_FN("CArcMgr");
  36. DC_END_FN();
  37. }
  38. CArcMgr::~CArcMgr()
  39. {
  40. DC_BEGIN_FN("~CArcMgr");
  41. DC_END_FN();
  42. }
  43. //
  44. // Static timer callback procedure
  45. // see platform SDK for params
  46. //
  47. VOID CALLBACK
  48. CArcMgr::sArcTimerCallBackProc(
  49. HWND hwnd,
  50. UINT uMsg,
  51. UINT_PTR idEvent,
  52. DWORD dwTime
  53. )
  54. {
  55. CArcMgr* pThis = NULL;
  56. DC_BEGIN_FN("sArcTimerCallBackProc");
  57. //
  58. // We pass the instance pointer around as the event id.
  59. //
  60. pThis = (CArcMgr*)idEvent;
  61. TRC_ASSERT(pThis,(TB,_T("sArcTimerCallBackProc got NULL idEvent")));
  62. if (pThis) {
  63. pThis->ArcTimerCallBackProc(hwnd, uMsg, idEvent, dwTime);
  64. }
  65. DC_END_FN();
  66. }
  67. //
  68. // Timer callback procedure
  69. // see platform SDK for params
  70. //
  71. VOID
  72. CArcMgr::ArcTimerCallBackProc(
  73. HWND hwnd,
  74. UINT uMsg,
  75. UINT_PTR idEvent,
  76. DWORD dwTime
  77. )
  78. {
  79. HRESULT hr = E_FAIL;
  80. DC_BEGIN_FN("ArcTimerCallBackProc");
  81. //
  82. // Kill the timers to make them one shot
  83. //
  84. if (!KillTimer(hwnd, idEvent)) {
  85. TRC_ERR((TB,_T("KillTimer for 0x%x failed with code 0x%x"),
  86. idEvent, GetLastError()));
  87. }
  88. if (_fContinueArc) {
  89. //
  90. // Attempt to kick off a reconnection attempt
  91. //
  92. hr = _pMsTscAx->Connect();
  93. if (FAILED(hr)) {
  94. TRC_ERR((TB,_T("Arc connect() failed with: 0x%x"),hr));
  95. //
  96. // Failed to initiate a connection so trigger a disconnect
  97. //
  98. _pMsTscAx->Disconnect();
  99. }
  100. }
  101. DC_END_FN();
  102. }
  103. //
  104. // Arc manager's notification that disconnection has occurred
  105. // This is the main entry point for driving autoreconnection
  106. //
  107. // Params:
  108. // [IN] disconnectReason - disconnection reason code
  109. // [IN] exReasonCode - extended disconnect reason code
  110. // [OUT] pfContinueDisconnect - returns TRUE if disconnect processing
  111. // shoud continue
  112. //
  113. // Returns:
  114. // Nothing
  115. //
  116. VOID
  117. CArcMgr::OnNotifyDisconnected(
  118. LONG disconnectReason,
  119. ExtendedDisconnectReasonCode exReasonCode,
  120. PBOOL pfContinueDisconnect
  121. )
  122. {
  123. BOOL fShouldAutoReconnect = FALSE;
  124. AutoReconnectContinueState arcContinue;
  125. HRESULT hr = E_FAIL;
  126. BOOL fContinueDisconnect = TRUE;
  127. CUI* pUI = NULL;
  128. BOOL fCoreAllowsArcContinue = FALSE;
  129. LONG maxArcConAttempts = MAX_ARC_CONNECTION_ATTEMPTS;
  130. DC_BEGIN_FN("OnNotifyDisconnected");
  131. TRC_ASSERT(_pMsTscAx,(TB,_T("_pMsTscAx is not set")));
  132. if (_pMsTscAx) {
  133. pUI = _pMsTscAx->GetCoreUI();
  134. TRC_ASSERT(pUI,(TB,_T("pUI is not set")));
  135. if (!(pUI->UI_IsCoreInitialized() &&
  136. pUI->UI_CanAutoReconnect() &&
  137. pUI->UI_GetEnableAutoReconnect())) {
  138. TRC_NRM((TB,_T("Skipping ARC core:%d canarc:%d arcenabled:%d"),
  139. pUI->UI_IsCoreInitialized(),
  140. pUI->UI_CanAutoReconnect(),
  141. pUI->UI_GetEnableAutoReconnect()));
  142. DC_QUIT;
  143. }
  144. maxArcConAttempts = pUI->UI_GetMaxArcAttempts();
  145. //
  146. // 1. Make a policy decision based on the disconnect reason
  147. // as to whether or not we should try to autoreconnect
  148. //
  149. //
  150. // If this is a network error then try to autoreconnect
  151. //
  152. if (IsNetworkError(disconnectReason, exReasonCode)) {
  153. fShouldAutoReconnect = TRUE;
  154. }
  155. if (fShouldAutoReconnect) {
  156. TRC_NRM((TB,_T("Proceeding with autoreconnect")));
  157. //
  158. // Reset continue flag on first attempt
  159. //
  160. if (0 == _nArcAttempts) {
  161. _fContinueArc = TRUE;
  162. }
  163. _nArcAttempts++;
  164. //
  165. // Default to automatic processing
  166. //
  167. arcContinue = autoReconnectContinueAutomatic;
  168. _fAutomaticArc = TRUE;
  169. //
  170. // 2.a) Fire the autoreconnection event to notify the core
  171. //
  172. pUI->UI_OnAutoReconnecting(disconnectReason,
  173. _nArcAttempts,
  174. maxArcConAttempts,
  175. &fCoreAllowsArcContinue);
  176. if (fCoreAllowsArcContinue) {
  177. //
  178. // 2.b) Fire the autoreconnection event to notify the container
  179. //
  180. hr = ((CProxy_IMsTscAxEvents<CMsTscAx>*)
  181. _pMsTscAx)->Fire_AutoReconnecting(
  182. disconnectReason,
  183. _nArcAttempts,
  184. &arcContinue
  185. );
  186. }
  187. else {
  188. //
  189. // Core said stop arc
  190. //
  191. TRC_NRM((TB,_T("Stopping arc in response to core request")));
  192. hr = S_OK;
  193. arcContinue = autoReconnectContinueStop;
  194. }
  195. //
  196. // If the event processing succeeded or if the caller did nothing
  197. // with it as in E_NOTIMPL then carry on
  198. //
  199. if (SUCCEEDED(hr) || E_NOTIMPL == hr) {
  200. //
  201. // 3. Take action depending on what the container requested
  202. //
  203. switch (arcContinue)
  204. {
  205. case autoReconnectContinueAutomatic:
  206. {
  207. //
  208. // 1) wait Ns then try to connect
  209. // 2) if get disconnected and land back in here
  210. // allow increment and retry up to n attemps
  211. //
  212. if (_nArcAttempts <= maxArcConAttempts) {
  213. //
  214. // For first try don't do any waiting
  215. // but still dispatch thru the same deferred
  216. // message code path. The timercallback will
  217. // kick off a connection attempt
  218. //
  219. UINT nDelay = (1 == _nArcAttempts) ?
  220. 0 : ARC_RECONNECTION_DELAY;
  221. if (SetTimer(_pMsTscAx->GetHwnd(),
  222. (UINT_PTR)(this),
  223. nDelay,
  224. sArcTimerCallBackProc)) {
  225. fContinueDisconnect = FALSE;
  226. }
  227. else {
  228. fContinueDisconnect = TRUE;
  229. TRC_ERR((TB,_T("Arc settimer failed: 0x%x"),
  230. GetLastError()));
  231. }
  232. }
  233. else {
  234. TRC_NRM((TB,
  235. _T("Arc exceed con attempts: %d of %d"),
  236. _nArcAttempts, maxArcConAttempts));
  237. fContinueDisconnect = TRUE;
  238. }
  239. }
  240. break;
  241. case autoReconnectContinueStop:
  242. {
  243. TRC_NRM((TB,
  244. _T("Container requested ARC continue stop")));
  245. }
  246. break;
  247. case autoReconnectContinueManual:
  248. {
  249. //
  250. // Flag that this is no longer automatic
  251. //
  252. _fAutomaticArc = FALSE;
  253. //
  254. // Just return, the container will drive
  255. // the process by calling AutoReconnect
  256. //
  257. fContinueDisconnect = FALSE;
  258. }
  259. break;
  260. default:
  261. {
  262. TRC_ERR((TB,_T("Unknown arcContinue code: 0x%x"),
  263. arcContinue));
  264. }
  265. break;
  266. }
  267. }
  268. else {
  269. TRC_ERR((TB,_T("Not arcing event ret hr: 0x%x"), hr));
  270. }
  271. }
  272. }
  273. DC_EXIT_POINT:
  274. *pfContinueDisconnect = fContinueDisconnect;
  275. DC_END_FN();
  276. }
  277. //
  278. // IsUserInitiatedDisconnect
  279. // Returns TRUE if the disconnection was initiated by the user
  280. //
  281. // Params:
  282. // disconnectReason - disconnection reason code
  283. // exReason - exteneded disconnection reason
  284. //
  285. BOOL
  286. CArcMgr::IsUserInitiatedDisconnect(
  287. LONG disconnectReason,
  288. ExtendedDisconnectReasonCode exReason
  289. )
  290. {
  291. ULONG mainDiscReason;
  292. BOOL fIsUserInitiated = FALSE;
  293. DC_BEGIN_FN("IsUserInitiatedDisconnect");
  294. //
  295. // REVIEW (nadima): mechanism to ensure new errors still work?
  296. //
  297. //
  298. // If this is a user-initiated disconnect, don't do a popup.
  299. //
  300. mainDiscReason = NL_GET_MAIN_REASON_CODE(disconnectReason);
  301. if (((disconnectReason !=
  302. UI_MAKE_DISCONNECT_ERR(UI_ERR_NORMAL_DISCONNECT)) &&
  303. (mainDiscReason != NL_DISCONNECT_REMOTE_BY_USER) &&
  304. (mainDiscReason != NL_DISCONNECT_LOCAL)) ||
  305. (exDiscReasonReplacedByOtherConnection == exReason)) {
  306. fIsUserInitiated = TRUE;
  307. }
  308. DC_END_FN();
  309. return fIsUserInitiated;
  310. }
  311. BOOL
  312. CArcMgr::IsNetworkError(
  313. LONG disconnectReason,
  314. ExtendedDisconnectReasonCode exReason
  315. )
  316. {
  317. BOOL fIsNetworkError = FALSE;
  318. ULONG mainReasonCode;
  319. DC_BEGIN_FN("IsNetworkError");
  320. mainReasonCode = NL_GET_MAIN_REASON_CODE(disconnectReason);
  321. if (((mainReasonCode == NL_DISCONNECT_ERROR) ||
  322. (UI_MAKE_DISCONNECT_ERR(UI_ERR_GHBNFAILED) == disconnectReason) ||
  323. (UI_MAKE_DISCONNECT_ERR(UI_ERR_DNSLOOKUPFAILED) == disconnectReason)) &&
  324. (exDiscReasonNoInfo == exReason)) {
  325. fIsNetworkError = TRUE;
  326. }
  327. DC_END_FN();
  328. return fIsNetworkError;
  329. }