|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
reconnect.c
Abstract:
Implements the support to enable the cluster API to transparently reconnect to a cluster when the node that the connection was made to fails.
This module contains wrappers for all the cluster RPC interfaces defined in api_rpc.idl. These wrappers filter out communication errors and attempt to reconnect to the cluster when a communication error occurs. This allows the caller to be completely ignorant of any node failures.
Author:
John Vert (jvert) 9/24/1996
Revision History:
--*/ #include "clusapip.h"
//
// Local function prototypes
//
DWORD ReconnectKeys( IN PCLUSTER Cluster );
DWORD ReopenKeyWorker( IN PCKEY Key );
DWORD ReconnectResources( IN PCLUSTER Cluster );
DWORD ReconnectGroups( IN PCLUSTER Cluster );
DWORD ReconnectNodes( IN PCLUSTER Cluster );
DWORD ReconnectNetworks( IN PCLUSTER Cluster );
DWORD ReconnectNetInterfaces( IN PCLUSTER Cluster );
DWORD ReconnectNotifySessions( IN PCLUSTER Cluster );
DWORD ReconnectCandidate( IN PCLUSTER Cluster, IN DWORD dwIndex, OUT PBOOL pIsContinue );
DWORD ReconnectCluster( IN PCLUSTER Cluster, IN DWORD Error, IN DWORD Generation ) /*++
Routine Description:
Attempts to reconnect to the specified cluster. The supplied error code is checked against RPC errors that indicate the server on the other end is unavailable. If it matches, a reconnect is attempted.
Arguments:
Cluster - Supplies the cluster.
Error - Supplies the error returned from RPC.
Generation - Supplies the cluster connection generation that was in effect when the error occurred.
Return Value:
ERROR_SUCCESS if the reconnect was successful and the RPC should be retried
Win32 error code otherwise.
--*/
{ //
// filter out all RPC errors that might indicate the connection
// has dropped.
//
switch (Error) { case RPC_S_CALL_FAILED: case ERROR_INVALID_HANDLE: case RPC_S_INVALID_BINDING: case RPC_S_SERVER_UNAVAILABLE: case RPC_S_SERVER_TOO_BUSY: case RPC_S_UNKNOWN_IF: case RPC_S_CALL_FAILED_DNE: case RPC_X_SS_IN_NULL_CONTEXT: case ERROR_CLUSTER_NODE_SHUTTING_DOWN: case EPT_S_NOT_REGISTERED: case ERROR_CLUSTER_NODE_NOT_READY: case RPC_S_UNKNOWN_AUTHN_SERVICE: TIME_PRINT(("Reconnect Cluster - reconnecting on Error %d\n",Error)); break;
default:
//
// Anything else we don't know how to deal with, so return
// the error directly.
//
return(Error); }
//
// Attempt to reconnect the cluster.
//
if ((Cluster->Flags & CLUS_DEAD) || (Cluster->Flags & CLUS_LOCALCONNECT)) { //
// Don't bother trying to reconnect. Either we've already
// declared the cluster dead, or the connection was over
// LPC (to the local machine) and we do not necessarily want
// to try to reconnect.
//
if (Cluster->Flags & CLUS_LOCALCONNECT) Cluster->Flags |= CLUS_DEAD; TIME_PRINT(("ReconnectCluster - Cluster dead or local, giving up - error %d\n",Error)); return(Error); } if (Generation < Cluster->Generation) { //
// We have already successfully reconnected since the error occurred,
// so retry immediately.
//
TIME_PRINT(("ReconnectCluster - Generation %d < Current %d, retrying\n", Generation, Cluster->Generation)); return(ERROR_SUCCESS); } EnterCriticalSection(&Cluster->Lock);
//
// Check again for cluster death, in case the previous owner
// of the lock declared the cluster dead.
//
if (Cluster->Flags & CLUS_DEAD) { TIME_PRINT(("ReconnectCluster - Cluster dead or local, giving up - error %d\n",Error)); LeaveCriticalSection(&Cluster->Lock); return(Error); }
if (Generation < Cluster->Generation) { //
// We have already reconnected since the error occurred,
// so retry immediately.
//
Error = ERROR_SUCCESS; TIME_PRINT(("ReconnectCluster - Generation %d < Current %d, retrying\n", Generation, Cluster->Generation)); } else { DWORD i, CurrentConnectionIndex = -1; BOOL IsContinue = TRUE; for (i=0; i<Cluster->ReconnectCount; i++) {
if (Cluster->Reconnect[i].IsCurrent) { //
// This is something we've already connected to and
// it's obviously gone, so skip this node.
//
TIME_PRINT(("ReconnectCluster - skipping current %ws\n", Cluster->Reconnect[i].Name)); CurrentConnectionIndex = i; continue; } if (!Cluster->Reconnect[i].IsUp) { //
// skip this candidate, it is not up.
//
// BUGBUG John Vert (jvert) 11/14/1996
// We could do another pass through the list if all
// the nodes that we think are up fail.
//
TIME_PRINT(("ReconnectCluster - skipping down node %ws\n", Cluster->Reconnect[i].Name)); continue; }
//
// Chittur Subbaraman (chitturs) - 08/29/1998
//
// Try to reconnect to the cluster using a candidate
//
Error = ReconnectCandidate ( Cluster, i, &IsContinue ); if (Error == ERROR_SUCCESS) { //
// Chittur Subbaraman (chitturs) - 08/29/1998
//
// Break out of the loop and return if you
// succeed in reconnecting
//
break; } if (IsContinue == FALSE) { //
// Chittur Subbaraman (chitturs) - 08/29/1998
//
// Exit immediately if you encounter an error
// that will not let you proceed any further
//
TIME_PRINT(("ReconnectCluster unable to continue - Exiting with code %d\n", Error)); goto error_exit; } } if (Error != ERROR_SUCCESS) { //
// Chittur Subbaraman (chitturs) - 08/29/98
//
// Try reconnecting with the current candidate (which
// you skipped before), if the CurrentConnectionIndex
// is valid and the party is up. This is required
// in the case of a 1 node cluster in which the
// client takes the cluster group offline. In this
// case, the current candidate (i.e., the node) is
// valid and the client should be able to retry and
// reconnect to the node.
//
if ((CurrentConnectionIndex != -1) && (Cluster->Reconnect[CurrentConnectionIndex].IsUp)) {
Error = ReconnectCandidate (Cluster, CurrentConnectionIndex, &IsContinue); if ((Error != ERROR_SUCCESS) && (IsContinue == FALSE)) { //
// Chittur Subbaraman (chitturs) - 08/29/1998
//
// Exit immediately if you encounter an error
// that will not let you proceed any further
//
TIME_PRINT(("ReconnectCluster - unable to continue for current party %ws - Exiting with code %d\n", Cluster->Reconnect[CurrentConnectionIndex].Name, Error)); goto error_exit; } } else { TIME_PRINT(("ReconnectCluster - unable to retry for current party %ws - Error %d\n", Cluster->Reconnect[CurrentConnectionIndex].Name, Error)); } if (Error != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCluster - all reconnects failed, giving up - error %d\n", Error)); Cluster->Flags |= CLUS_DEAD; } } } error_exit: LeaveCriticalSection(&Cluster->Lock); return(Error); }
DWORD ReconnectKeys( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster registry keys after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCKEY Key; DWORD Status;
ListEntry = Cluster->KeyList.Flink; while (ListEntry != &Cluster->KeyList) {
//
// Each key in the cluster's list represents the
// root of a registry tree.
//
Key = CONTAINING_RECORD(ListEntry, CKEY, ParentList); ListEntry = ListEntry->Flink;
Status = ReopenKeyWorker(Key); if (Status != ERROR_SUCCESS) { return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReopenKeyWorker( IN PCKEY Key ) /*++
Routine Description:
Recursive worker routine for opening a key and all its children.
Arguments:
Key - Supplies the root key to reopen.
Return Value:
ERROR_SUCCESS if successful.
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCKEY Child; DWORD Status = ERROR_GEN_FAILURE; BOOL CloseAfterOpen;
if (Key->RemoteKey != NULL) { //
// Destroy the old context
//
Status = MyRpcSmDestroyClientContext(Key->Cluster, &Key->RemoteKey); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReopenKeyWorker - RpcSmDestroyClientContext failed Error %d\n",Status)); } CloseAfterOpen = FALSE; } else { CloseAfterOpen = TRUE; }
//
// Next, reopen this key.
//
if (Key->Parent == NULL) { Key->RemoteKey = ApiGetRootKey(Key->Cluster->RpcBinding, Key->SamDesired, &Status); } else { Key->RemoteKey = ApiOpenKey(Key->Parent->RemoteKey, Key->RelativeName, Key->SamDesired, &Status); } if (Key->RemoteKey == NULL) { return(Status); }
//
// Now open all this keys children recursively.
//
ListEntry = Key->ChildList.Flink; while (ListEntry != &Key->ChildList) { Child = CONTAINING_RECORD(ListEntry, CKEY, ParentList); ListEntry = ListEntry->Flink;
Status = ReopenKeyWorker(Child); if (Status != ERROR_SUCCESS) { return(Status); } }
//
// If the key had been closed and was just kept around to do the reopens, close it
// now as the reopens are done.
//
if (CloseAfterOpen) { ApiCloseKey(&Key->RemoteKey); }
return(ERROR_SUCCESS); }
DWORD ReconnectResources( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster resources after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCRESOURCE Resource; DWORD Status;
ListEntry = Cluster->ResourceList.Flink; while (ListEntry != &Cluster->ResourceList) { Resource = CONTAINING_RECORD(ListEntry, CRESOURCE, ListEntry); ListEntry = ListEntry->Flink;
//
// Close the current RPC handle.
//
TIME_PRINT(("ReconnectResources - destroying context %08lx\n",Resource->hResource)); Status = MyRpcSmDestroyClientContext(Cluster, &Resource->hResource); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectResources - RpcSmDestroyClientContext failed Error %d\n",Status)); }
//
// Open a new RPC handle.
//
Resource->hResource = ApiOpenResource(Cluster->RpcBinding, Resource->Name, &Status); if (Resource->hResource == NULL) { TIME_PRINT(("ReconnectResources: failed to reopen resource %ws\n",Resource->Name)); return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReconnectGroups( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster groups after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCGROUP Group; DWORD Status;
ListEntry = Cluster->GroupList.Flink; while (ListEntry != &Cluster->GroupList) { Group = CONTAINING_RECORD(ListEntry, CGROUP, ListEntry); ListEntry = ListEntry->Flink;
//
// Close the old RPC handle
//
TIME_PRINT(("ReconnectGroups - destroying context %08lx\n",Group->hGroup)); Status = MyRpcSmDestroyClientContext(Cluster, &Group->hGroup); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectGroups - RpcSmDestroyClientContext failed Error %d\n",Status)); }
//
// Open a new RPC handle.
//
Group->hGroup = ApiOpenGroup(Cluster->RpcBinding, Group->Name, &Status); if (Group->hGroup == NULL) { return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReconnectNodes( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster nodes after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCNODE Node; DWORD Status;
ListEntry = Cluster->NodeList.Flink; while (ListEntry != &Cluster->NodeList) { Node = CONTAINING_RECORD(ListEntry, CNODE, ListEntry); ListEntry = ListEntry->Flink;
//
// Close the old RPC handle.
//
TIME_PRINT(("ReconnectNodes - destroying context %08lx\n",Node->hNode)); Status = MyRpcSmDestroyClientContext(Cluster, &Node->hNode); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectNodes - RpcSmDestroyClientContext failed Error %d\n",Status)); }
//
// Open a new RPC handle.
//
Node->hNode = ApiOpenNode(Cluster->RpcBinding, Node->Name, &Status); if (Node->hNode == NULL) { return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReconnectNetworks( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster networks after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCNETWORK Network; DWORD Status;
ListEntry = Cluster->NetworkList.Flink; while (ListEntry != &Cluster->NetworkList) {
Network = CONTAINING_RECORD(ListEntry, CNETWORK, ListEntry); ListEntry = ListEntry->Flink;
//
// Close the old RPC handle.
//
TIME_PRINT(("ReconnectNetworks - destroying context %08lx\n",Network->hNetwork)); Status = MyRpcSmDestroyClientContext(Cluster, &Network->hNetwork);
if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectNetworks - RpcSmDestroyClientContext failed Error %d\n",Status)); }
//
// Open a new RPC handle.
//
Network->hNetwork = ApiOpenNetwork(Cluster->RpcBinding, Network->Name, &Status);
if (Network->hNetwork == NULL) { return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReconnectNetInterfaces( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster network interfaces after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry; PCNETINTERFACE NetInterface; DWORD Status;
ListEntry = Cluster->NetInterfaceList.Flink; while (ListEntry != &Cluster->NetInterfaceList) {
NetInterface = CONTAINING_RECORD(ListEntry, CNETINTERFACE, ListEntry); ListEntry = ListEntry->Flink;
//
// Close the old RPC handle.
//
TIME_PRINT(("ReconnectNetInterfaces - destroying context %08lx\n",NetInterface->hNetInterface)); Status = MyRpcSmDestroyClientContext(Cluster, &NetInterface->hNetInterface);
if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectNetInterfaces - RpcSmDestroyClientContext failed Error %d\n",Status)); }
//
// Open a new RPC handle.
//
NetInterface->hNetInterface = ApiOpenNetInterface(Cluster->RpcBinding, NetInterface->Name, &Status);
if (NetInterface->hNetInterface == NULL) { return(Status); } }
return(ERROR_SUCCESS); }
DWORD ReconnectNotifySessions( IN PCLUSTER Cluster ) /*++
Routine Description:
Reopens all cluster notify sessions after a reconnect
Arguments:
Cluster - Supplies the cluster to be reconnected.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ PLIST_ENTRY ListEntry, NotifyListEntry; PCNOTIFY_SESSION Session; DWORD Status; PCNOTIFY_PACKET Packet = NULL; PLIST_ENTRY EventEntry; PCNOTIFY_EVENT NotifyEvent; LPCWSTR Name;
ListEntry = Cluster->SessionList.Flink; while (ListEntry != &Cluster->SessionList) { Session = CONTAINING_RECORD(ListEntry, CNOTIFY_SESSION, ClusterList); ListEntry = ListEntry->Flink;
//
// Close the old RPC handle.
//
TIME_PRINT(("ReconnectNotifySessions - destroying context 0x%08lx\n",Session->hNotify)); //close the old port, since the reconnect may connect to the same
//node again
Status = ApiCloseNotify(&Session->hNotify); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectNotifySessions - ApiCloseNotify failed %d\n", Status)); Status = MyRpcSmDestroyClientContext(Cluster, &Session->hNotify); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectNotifySessions - RpcSmDestroyClientContext failed Error %d\n",Status)); } } //
// Open a new RPC handle.
//
TIME_PRINT(("ReconnectNotifySessions - Calling ApiCreateNotify\n")); Session->hNotify = ApiCreateNotify(Cluster->RpcBinding, &Status); if (Session->hNotify == NULL) { return(Status); }
TIME_PRINT(("ReconnectNotifySessions - Session=0x%08lx Notify=0x%08x\n", Session, Session->hNotify));
//
// Now repost all the notifications
//
EventEntry = Session->EventList.Flink; while (EventEntry != &Session->EventList) { NotifyEvent = CONTAINING_RECORD(EventEntry, CNOTIFY_EVENT, ListEntry); EventEntry = EventEntry->Flink;
TIME_PRINT(("ReconnectNotifySession: registering event type %lx\n",NotifyEvent->dwFilter)); Status = ReRegisterNotifyEvent(Session, NotifyEvent, NULL); if (Status != ERROR_SUCCESS) { return(Status); } }
// Run down the notify list for this cluster and post a packet for
// each registered notify event for CLUSTER_CHANGE_RECONNECT_EVENT
//
Name = Cluster->ClusterName; NotifyListEntry = Cluster->NotifyList.Flink; while (NotifyListEntry != &Cluster->NotifyList) { NotifyEvent = CONTAINING_RECORD(NotifyListEntry, CNOTIFY_EVENT, ObjectList); if (NotifyEvent->dwFilter & CLUSTER_CHANGE_CLUSTER_RECONNECT) { if (Packet == NULL) { Packet = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_PACKET)); if (Packet == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } } //SS: Dont know what the Status was meant for
//It looks like it is not being used
Packet->Status = ERROR_SUCCESS; Packet->Filter = CLUSTER_CHANGE_CLUSTER_RECONNECT; Packet->KeyId = NotifyEvent->EventId; Packet->Name = MIDL_user_allocate((lstrlenW(Name)+1)*sizeof(WCHAR)); if (Packet->Name != NULL) { lstrcpyW(Packet->Name, Name); } TIME_PRINT(("NotifyThread - posting CLUSTER_CHANGE_CLUSTER_RECONNECT to notify queue\n")); ClRtlInsertTailQueue(&Session->ParentNotify->Queue, &Packet->ListEntry); Packet = NULL; } NotifyListEntry = NotifyListEntry->Flink; } }
return(ERROR_SUCCESS); }
DWORD GetReconnectCandidates( IN PCLUSTER Cluster ) /*++
Routine Description:
Computes the list of reconnect candidates that will be used in case of a connection failure.
Arguments:
Cluster - supplies the cluster
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{ DWORD Status; PENUM_LIST EnumList = NULL; DWORD i;
//
// Real bad algorithm here, just get a list of all the nodes
//
Status = ApiCreateEnum(Cluster->RpcBinding, CLUSTER_ENUM_NODE, &EnumList); if (Status != ERROR_SUCCESS) { return(Status); }
Cluster->ReconnectCount = EnumList->EntryCount + 1; Cluster->Reconnect = LocalAlloc(LMEM_FIXED, sizeof(RECONNECT_CANDIDATE)*Cluster->ReconnectCount); if (Cluster->Reconnect == NULL) { MIDL_user_free(EnumList); return(ERROR_NOT_ENOUGH_MEMORY); } for (i=0; i<Cluster->ReconnectCount-1; i++) { Cluster->Reconnect[i].IsUp = TRUE; Cluster->Reconnect[i].Name = EnumList->Entry[i].Name; if (lstrcmpiW(Cluster->Reconnect[i].Name, Cluster->NodeName) == 0) { Cluster->Reconnect[i].IsCurrent = TRUE; } else { Cluster->Reconnect[i].IsCurrent = FALSE; } } MIDL_user_free(EnumList);
//
// Now add the cluster name.
//
Cluster->Reconnect[i].IsUp = TRUE; Cluster->Reconnect[i].Name = MIDL_user_allocate((lstrlenW(Cluster->ClusterName)+1)*sizeof(WCHAR)); if (Cluster->Reconnect[i].Name == NULL) { //
// Just forget about the cluster name.
//
--Cluster->ReconnectCount; } else { lstrcpyW(Cluster->Reconnect[i].Name, Cluster->ClusterName); Cluster->Reconnect[i].IsCurrent = FALSE; }
return(ERROR_SUCCESS); }
VOID FreeReconnectCandidates( IN PCLUSTER Cluster ) /*++
Routine Description:
Frees and cleans up any reconnect candidates
Arguments:
Cluster - Supplies the cluster
Return Value:
None.
--*/
{ DWORD i;
for (i=0; i<Cluster->ReconnectCount; i++) { MIDL_user_free(Cluster->Reconnect[i].Name); } LocalFree(Cluster->Reconnect); Cluster->Reconnect = NULL; Cluster->ReconnectCount = 0; }
DWORD ReconnectCandidate( IN PCLUSTER Cluster, IN DWORD dwIndex, OUT PBOOL pIsContinue ) /*++
Routine Description:
Try to reconnect to the cluster using a reconnection candidate. Called with lock held.
Arguments:
Cluster - Supplies the cluster
dwIndex - Supplies the index of the reconnection candidate in the Cluster->Reconnect[] array
pIsContinue - Helps decide whether to continue trying reconnection with other candidates in case this try with the current candidate fails
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/ { LPWSTR NewClusterName; LPWSTR NewNodeName; WCHAR *Binding = NULL; RPC_BINDING_HANDLE NewBinding; RPC_BINDING_HANDLE OldBinding; DWORD Status, j; //
// Go ahead and try the reconnect.
//
TIME_PRINT(("ReconnectCandidate - Binding to %ws\n",Cluster->Reconnect[dwIndex].Name)); Status = RpcStringBindingComposeW(L"b97db8b2-4c63-11cf-bff6-08002be23f2f", L"ncadg_ip_udp", Cluster->Reconnect[dwIndex].Name, NULL, NULL, &Binding); if (Status != RPC_S_OK) { TIME_PRINT(("ReconnectCandidate - RpcStringBindingComposeW failed %d\n", Status)); *pIsContinue = FALSE; return(Status); } Status = RpcBindingFromStringBindingW(Binding, &NewBinding); RpcStringFreeW(&Binding); if (Status != RPC_S_OK) { TIME_PRINT(("ReconnectCandidate - RpcBindingFromStringBindingW failed %d\n", Status)); *pIsContinue = FALSE; return(Status); }
//
// Resolve the binding handle endpoint
//
TIME_PRINT(("ReconnectCluster - resolving binding endpoint\n")); Status = RpcEpResolveBinding(NewBinding, clusapi_v2_0_c_ifspec); if (Status != RPC_S_OK) { TIME_PRINT(("ReconnectCandidate - RpcEpResolveBinding failed %d\n", Status)); *pIsContinue = TRUE; return(Status); } TIME_PRINT(("ReconnectCandidate - binding endpoint resolved\n")); //
// Set authentication information
//
Status = RpcBindingSetAuthInfoW(NewBinding, NULL, Cluster->AuthnLevel, RPC_C_AUTHN_WINNT, NULL, RPC_C_AUTHZ_NAME); if (Status != RPC_S_OK) { TIME_PRINT(("ReconnectCandidate - RpcBindingSetAuthInfoW failed %d\n", Status)); *pIsContinue = FALSE; return(Status); } OldBinding = Cluster->RpcBinding; Cluster->RpcBinding = NewBinding; MyRpcBindingFree(Cluster, &OldBinding);
//
// Now that we have a binding, get the cluster name and node name.
//
NewClusterName = NewNodeName = NULL; Status = ApiGetClusterName(Cluster->RpcBinding, &NewClusterName, &NewNodeName); if (Status != RPC_S_OK) { //
// Try the next candidate in our list.
//
TIME_PRINT(("ReconnectCandidate - ApiGetClusterName failed %d\n",Status)); *pIsContinue = TRUE; return(Status); } TIME_PRINT(("ReconnectCandidate - ApiGetClusterName succeeded, reopening handles\n",Status)); MIDL_user_free(Cluster->ClusterName); MIDL_user_free(Cluster->NodeName); Cluster->ClusterName = NewClusterName; Cluster->NodeName = NewNodeName; if (Cluster->hCluster != NULL) { MyRpcSmDestroyClientContext(Cluster, &Cluster->hCluster); } Cluster->hCluster = ApiOpenCluster(Cluster->RpcBinding, &Status); if (Cluster->hCluster == NULL) { TIME_PRINT(("ReconnectCandidate - ApiOpenCluster failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
//
// We got this far, so assume we have a valid connection to a new server.
// Reopen the cluster objects.
//
Status = ReconnectKeys(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectKeys failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
Status = ReconnectResources(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectResources failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
Status = ReconnectGroups(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectGroups failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
Status = ReconnectNodes(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectNodes failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
Status = ReconnectNetworks(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectNetworks failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
Status = ReconnectNetInterfaces(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectNetInterfaces failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
//
// Finally, reissue clusterwide notification events.
//
Status = ReconnectNotifySessions(Cluster); if (Status != ERROR_SUCCESS) { TIME_PRINT(("ReconnectCandidate - ReconnectNotifySessions failed %d\n", Status)); *pIsContinue = TRUE; return(Status); }
//
// We have successfully reconnected!
//
++Cluster->Generation;
//
// Mark all the other reconnect candidates as not the current.
// Mark the successful reconnect candidate as current.
//
for (j=0; j<Cluster->ReconnectCount; j++) { if (j != dwIndex) { Cluster->Reconnect[j].IsCurrent = FALSE; } else { Cluster->Reconnect[dwIndex].IsCurrent = TRUE; } } TIME_PRINT(("ReconnectCandidate - successful!\n", Status)); return (ERROR_SUCCESS); }
|