Windows2003-3790/termsrv/newclient/mstscax/arcmgr.cpp
2020-09-30 16:53:55 +02:00

397 lines
11 KiB
C++

//
// 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;
}