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
396 lines
11 KiB
//
|
|
// Module : arcmgr.cpp
|
|
//
|
|
// Class : CArcMgr
|
|
//
|
|
// Purpose: AutoReconnection mananger class - drives policy for
|
|
// ts client autoreconnection
|
|
//
|
|
// Copyright(C) Microsoft Corporation 2001
|
|
//
|
|
// Author : Nadim Abdo (nadima)
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "atlwarn.h"
|
|
|
|
BEGIN_EXTERN_C
|
|
#define TRC_GROUP TRC_GROUP_UI
|
|
#define TRC_FILE "arcmgr"
|
|
#include <atrcapi.h>
|
|
END_EXTERN_C
|
|
|
|
//Header generated from IDL
|
|
#include "mstsax.h"
|
|
#include "mstscax.h"
|
|
#include "arcmgr.h"
|
|
#include "tscerrs.h"
|
|
|
|
//
|
|
// Total time to wait between ARC attempts
|
|
//
|
|
#define ARC_RECONNECTION_DELAY (3000)
|
|
|
|
|
|
CArcMgr::CArcMgr() :
|
|
_pMsTscAx(NULL),
|
|
_nArcAttempts(0),
|
|
_fAutomaticArc(TRUE),
|
|
_fContinueArc(FALSE)
|
|
{
|
|
DC_BEGIN_FN("CArcMgr");
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
CArcMgr::~CArcMgr()
|
|
{
|
|
DC_BEGIN_FN("~CArcMgr");
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Static timer callback procedure
|
|
// see platform SDK for params
|
|
//
|
|
VOID CALLBACK
|
|
CArcMgr::sArcTimerCallBackProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
UINT_PTR idEvent,
|
|
DWORD dwTime
|
|
)
|
|
{
|
|
CArcMgr* pThis = NULL;
|
|
DC_BEGIN_FN("sArcTimerCallBackProc");
|
|
|
|
//
|
|
// We pass the instance pointer around as the event id.
|
|
//
|
|
pThis = (CArcMgr*)idEvent;
|
|
TRC_ASSERT(pThis,(TB,_T("sArcTimerCallBackProc got NULL idEvent")));
|
|
if (pThis) {
|
|
pThis->ArcTimerCallBackProc(hwnd, uMsg, idEvent, dwTime);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Timer callback procedure
|
|
// see platform SDK for params
|
|
//
|
|
VOID
|
|
CArcMgr::ArcTimerCallBackProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
UINT_PTR idEvent,
|
|
DWORD dwTime
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DC_BEGIN_FN("ArcTimerCallBackProc");
|
|
|
|
//
|
|
// Kill the timers to make them one shot
|
|
//
|
|
if (!KillTimer(hwnd, idEvent)) {
|
|
TRC_ERR((TB,_T("KillTimer for 0x%x failed with code 0x%x"),
|
|
idEvent, GetLastError()));
|
|
}
|
|
|
|
|
|
if (_fContinueArc) {
|
|
//
|
|
// Attempt to kick off a reconnection attempt
|
|
//
|
|
hr = _pMsTscAx->Connect();
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Arc connect() failed with: 0x%x"),hr));
|
|
|
|
//
|
|
// Failed to initiate a connection so trigger a disconnect
|
|
//
|
|
_pMsTscAx->Disconnect();
|
|
}
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Arc manager's notification that disconnection has occurred
|
|
// This is the main entry point for driving autoreconnection
|
|
//
|
|
// Params:
|
|
// [IN] disconnectReason - disconnection reason code
|
|
// [IN] exReasonCode - extended disconnect reason code
|
|
// [OUT] pfContinueDisconnect - returns TRUE if disconnect processing
|
|
// shoud continue
|
|
//
|
|
// Returns:
|
|
// Nothing
|
|
//
|
|
VOID
|
|
CArcMgr::OnNotifyDisconnected(
|
|
LONG disconnectReason,
|
|
ExtendedDisconnectReasonCode exReasonCode,
|
|
PBOOL pfContinueDisconnect
|
|
)
|
|
{
|
|
BOOL fShouldAutoReconnect = FALSE;
|
|
AutoReconnectContinueState arcContinue;
|
|
HRESULT hr = E_FAIL;
|
|
BOOL fContinueDisconnect = TRUE;
|
|
CUI* pUI = NULL;
|
|
BOOL fCoreAllowsArcContinue = FALSE;
|
|
LONG maxArcConAttempts = MAX_ARC_CONNECTION_ATTEMPTS;
|
|
|
|
DC_BEGIN_FN("OnNotifyDisconnected");
|
|
|
|
TRC_ASSERT(_pMsTscAx,(TB,_T("_pMsTscAx is not set")));
|
|
|
|
if (_pMsTscAx) {
|
|
|
|
pUI = _pMsTscAx->GetCoreUI();
|
|
TRC_ASSERT(pUI,(TB,_T("pUI is not set")));
|
|
|
|
if (!(pUI->UI_IsCoreInitialized() &&
|
|
pUI->UI_CanAutoReconnect() &&
|
|
pUI->UI_GetEnableAutoReconnect())) {
|
|
|
|
TRC_NRM((TB,_T("Skipping ARC core:%d canarc:%d arcenabled:%d"),
|
|
pUI->UI_IsCoreInitialized(),
|
|
pUI->UI_CanAutoReconnect(),
|
|
pUI->UI_GetEnableAutoReconnect()));
|
|
DC_QUIT;
|
|
|
|
}
|
|
|
|
maxArcConAttempts = pUI->UI_GetMaxArcAttempts();
|
|
|
|
//
|
|
// 1. Make a policy decision based on the disconnect reason
|
|
// as to whether or not we should try to autoreconnect
|
|
//
|
|
|
|
//
|
|
// If this is a network error then try to autoreconnect
|
|
//
|
|
if (IsNetworkError(disconnectReason, exReasonCode)) {
|
|
fShouldAutoReconnect = TRUE;
|
|
}
|
|
|
|
if (fShouldAutoReconnect) {
|
|
|
|
TRC_NRM((TB,_T("Proceeding with autoreconnect")));
|
|
|
|
//
|
|
// Reset continue flag on first attempt
|
|
//
|
|
if (0 == _nArcAttempts) {
|
|
_fContinueArc = TRUE;
|
|
}
|
|
_nArcAttempts++;
|
|
|
|
//
|
|
// Default to automatic processing
|
|
//
|
|
arcContinue = autoReconnectContinueAutomatic;
|
|
_fAutomaticArc = TRUE;
|
|
|
|
//
|
|
// 2.a) Fire the autoreconnection event to notify the core
|
|
//
|
|
pUI->UI_OnAutoReconnecting(disconnectReason,
|
|
_nArcAttempts,
|
|
maxArcConAttempts,
|
|
&fCoreAllowsArcContinue);
|
|
|
|
if (fCoreAllowsArcContinue) {
|
|
//
|
|
// 2.b) Fire the autoreconnection event to notify the container
|
|
//
|
|
hr = ((CProxy_IMsTscAxEvents<CMsTscAx>*)
|
|
_pMsTscAx)->Fire_AutoReconnecting(
|
|
disconnectReason,
|
|
_nArcAttempts,
|
|
&arcContinue
|
|
);
|
|
}
|
|
else {
|
|
//
|
|
// Core said stop arc
|
|
//
|
|
TRC_NRM((TB,_T("Stopping arc in response to core request")));
|
|
hr = S_OK;
|
|
arcContinue = autoReconnectContinueStop;
|
|
}
|
|
|
|
//
|
|
// If the event processing succeeded or if the caller did nothing
|
|
// with it as in E_NOTIMPL then carry on
|
|
//
|
|
if (SUCCEEDED(hr) || E_NOTIMPL == hr) {
|
|
|
|
//
|
|
// 3. Take action depending on what the container requested
|
|
//
|
|
switch (arcContinue)
|
|
{
|
|
case autoReconnectContinueAutomatic:
|
|
{
|
|
//
|
|
// 1) wait Ns then try to connect
|
|
// 2) if get disconnected and land back in here
|
|
// allow increment and retry up to n attemps
|
|
//
|
|
|
|
if (_nArcAttempts <= maxArcConAttempts) {
|
|
//
|
|
// For first try don't do any waiting
|
|
// but still dispatch thru the same deferred
|
|
// message code path. The timercallback will
|
|
// kick off a connection attempt
|
|
//
|
|
UINT nDelay = (1 == _nArcAttempts) ?
|
|
0 : ARC_RECONNECTION_DELAY;
|
|
if (SetTimer(_pMsTscAx->GetHwnd(),
|
|
(UINT_PTR)(this),
|
|
nDelay,
|
|
sArcTimerCallBackProc)) {
|
|
fContinueDisconnect = FALSE;
|
|
}
|
|
else {
|
|
fContinueDisconnect = TRUE;
|
|
TRC_ERR((TB,_T("Arc settimer failed: 0x%x"),
|
|
GetLastError()));
|
|
}
|
|
|
|
}
|
|
else {
|
|
TRC_NRM((TB,
|
|
_T("Arc exceed con attempts: %d of %d"),
|
|
_nArcAttempts, maxArcConAttempts));
|
|
fContinueDisconnect = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case autoReconnectContinueStop:
|
|
{
|
|
TRC_NRM((TB,
|
|
_T("Container requested ARC continue stop")));
|
|
}
|
|
break;
|
|
|
|
case autoReconnectContinueManual:
|
|
{
|
|
//
|
|
// Flag that this is no longer automatic
|
|
//
|
|
_fAutomaticArc = FALSE;
|
|
|
|
//
|
|
// Just return, the container will drive
|
|
// the process by calling AutoReconnect
|
|
//
|
|
fContinueDisconnect = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
TRC_ERR((TB,_T("Unknown arcContinue code: 0x%x"),
|
|
arcContinue));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB,_T("Not arcing event ret hr: 0x%x"), hr));
|
|
}
|
|
}
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
*pfContinueDisconnect = fContinueDisconnect;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// IsUserInitiatedDisconnect
|
|
// Returns TRUE if the disconnection was initiated by the user
|
|
//
|
|
// Params:
|
|
// disconnectReason - disconnection reason code
|
|
// exReason - exteneded disconnection reason
|
|
//
|
|
BOOL
|
|
CArcMgr::IsUserInitiatedDisconnect(
|
|
LONG disconnectReason,
|
|
ExtendedDisconnectReasonCode exReason
|
|
)
|
|
{
|
|
ULONG mainDiscReason;
|
|
BOOL fIsUserInitiated = FALSE;
|
|
|
|
DC_BEGIN_FN("IsUserInitiatedDisconnect");
|
|
|
|
//
|
|
// REVIEW (nadima): mechanism to ensure new errors still work?
|
|
//
|
|
|
|
//
|
|
// If this is a user-initiated disconnect, don't do a popup.
|
|
//
|
|
mainDiscReason = NL_GET_MAIN_REASON_CODE(disconnectReason);
|
|
|
|
if (((disconnectReason !=
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_NORMAL_DISCONNECT)) &&
|
|
(mainDiscReason != NL_DISCONNECT_REMOTE_BY_USER) &&
|
|
(mainDiscReason != NL_DISCONNECT_LOCAL)) ||
|
|
(exDiscReasonReplacedByOtherConnection == exReason)) {
|
|
|
|
fIsUserInitiated = TRUE;
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fIsUserInitiated;
|
|
}
|
|
|
|
BOOL
|
|
CArcMgr::IsNetworkError(
|
|
LONG disconnectReason,
|
|
ExtendedDisconnectReasonCode exReason
|
|
)
|
|
{
|
|
BOOL fIsNetworkError = FALSE;
|
|
ULONG mainReasonCode;
|
|
|
|
DC_BEGIN_FN("IsNetworkError");
|
|
|
|
mainReasonCode = NL_GET_MAIN_REASON_CODE(disconnectReason);
|
|
|
|
if (((mainReasonCode == NL_DISCONNECT_ERROR) ||
|
|
(UI_MAKE_DISCONNECT_ERR(UI_ERR_GHBNFAILED) == disconnectReason) ||
|
|
(UI_MAKE_DISCONNECT_ERR(UI_ERR_DNSLOOKUPFAILED) == disconnectReason)) &&
|
|
(exDiscReasonNoInfo == exReason)) {
|
|
|
|
fIsNetworkError = TRUE;
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fIsNetworkError;
|
|
}
|
|
|
|
|