windows-nt/Source/XPSP1/NT/base/cluster/clusapi/nodeapi.c
2020-09-26 16:20:57 +08:00

579 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
nodeapi.c
Abstract:
Public interfaces for managing cluster nodes.
Author:
John Vert (jvert) 15-Jan-1996
Revision History:
--*/
#include "clusapip.h"
//
// Cluster Node Management Routines.
//
HNODE
WINAPI
OpenClusterNode(
IN HCLUSTER hCluster,
IN LPCWSTR lpszNodeName
)
/*++
Routine Description:
Opens an individual node in the cluster.
Arguments:
hCluster - Supplies a cluster handle returned from OpenCluster.
lpszNodeName - Supplies the name of the individual node to open.
Return Value:
non-NULL - returns an open handle to the specified cluster.
NULL - The operation failed. Extended error status is available
using GetLastError()
--*/
{
PCLUSTER Cluster;
PCNODE Node;
error_status_t Status = ERROR_SUCCESS;
Cluster = (PCLUSTER)hCluster;
Node = LocalAlloc(LMEM_FIXED, sizeof(CNODE));
if (Node == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(NULL);
}
Node->Name = LocalAlloc(LMEM_FIXED, (lstrlenW(lpszNodeName)+1)*sizeof(WCHAR));
if (Node->Name == NULL) {
LocalFree(Node);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(NULL);
}
lstrcpyW(Node->Name, lpszNodeName);
Node->Cluster = Cluster;
InitializeListHead(&Node->NotifyList);
WRAP_NULL(Node->hNode,
(ApiOpenNode(Cluster->RpcBinding,
lpszNodeName,
&Status)),
&Status,
Cluster);
if ((Node->hNode == NULL) || (Status != ERROR_SUCCESS)) {
LocalFree(Node->Name);
LocalFree(Node);
SetLastError(Status);
return(NULL);
}
//
// Link newly opened Node onto the cluster structure.
//
EnterCriticalSection(&Cluster->Lock);
InsertHeadList(&Cluster->NodeList, &Node->ListEntry);
LeaveCriticalSection(&Cluster->Lock);
return((HNODE)Node);
}
BOOL
WINAPI
CloseClusterNode(
IN HNODE hNode
)
/*++
Routine Description:
Closes a handle to an individual cluster node
Arguments:
hNode - Supplies the cluster node to be closed
Return Value:
TRUE - The operation was successful.
FALSE - The operation failed. Extended error status is available
using GetLastError()
--*/
{
PCNODE Node;
PCLUSTER Cluster;
Node = (PCNODE)hNode;
Cluster = (PCLUSTER)Node->Cluster;
//
// Unlink node from cluster list.
//
EnterCriticalSection(&Cluster->Lock);
RemoveEntryList(&Node->ListEntry);
//
// Remove any notifications posted against this resource.
//
RundownNotifyEvents(&Node->NotifyList, Node->Name);
//if the cluster is dead and the reconnect has failed,
//the Node->hNode might be NULL if s_apiopennode for
//this node failed on a reconnect
//the cluster may be dead and hNode may be non null, say
//if reconnectnodes succeeded but the reconnectnetworks
//failed
// At reconnect, the old context is saved in the obsolete
// list for deletion when the cluster handle is closed
if ((Cluster->Flags & CLUS_DEAD) && (Node->hNode)) {
RpcSmDestroyClientContext(&Node->hNode);
LeaveCriticalSection(&Cluster->Lock);
goto FnExit;
}
LeaveCriticalSection(&Cluster->Lock);
//
// Close RPC context handle
//
ApiCloseNode(&Node->hNode);
FnExit:
//
// Free memory allocations
//
LocalFree(Node->Name);
LocalFree(Node);
//
// Give the cluster a chance to clean up in case this
// node was the only thing keeping it around.
//
CleanupCluster(Cluster);
return(TRUE);
}
#undef GetCurrentClusterNodeId
DWORD
GetCurrentClusterNodeId(
OUT LPWSTR lpszNodeId,
IN OUT LPDWORD lpcchName
)
/*++
Routine Description:
Returns the node identifier of the current node. This function
is only available on a node that is currently online and a member
of a cluster.
Arguments:
lpszNodeId - Points to a buffer that receives the unique ID of the object,
including the terminating null character.
lpcchName - Points to a variable that specifies the size, in characters
of the buffer pointed to by the lpszNodeId parameter. This size
should include the terminating null character. When the function
returns, the variable pointed to be lpcchName contains the number
of characters stored in the buffer. The count returned does not
include the terminating null character.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{
HCLUSTER Cluster;
HNODE CurrentNode;
DWORD Status;
Cluster = OpenCluster(NULL);
if (Cluster == NULL) {
return(GetLastError());
}
CurrentNode = OpenClusterNode(Cluster,
((PCLUSTER)Cluster)->NodeName);
if (CurrentNode != NULL) {
Status = GetClusterNodeId(CurrentNode,
lpszNodeId,
lpcchName);
CloseClusterNode(CurrentNode);
}
else
{
Status = GetLastError();
}
CloseCluster(Cluster);
return(Status);
}
DWORD
WINAPI
GetClusterNodeId(
IN HNODE hNode,
OUT LPWSTR lpszNodeId,
IN OUT LPDWORD lpcchName
)
/*++
Routine Description:
Returns the unique identifier of the specified node
Arguments:
hNode - Supplies the node whose unique ID is to be returned.
lpszNodeId - Points to a buffer that receives the unique ID of the object,
including the terminating null character.
lpcchName - Points to a variable that specifies the size, in characters
of the buffer pointed to by the lpszNodeId parameter. This size
should include the terminating null character. When the function
returns, the variable pointed to be lpcchName contains the number
of characters stored in the buffer. The count returned does not
include the terminating null character.
Return Value:
If the function succeeds, the return value is ERROR_SUCCESS.
If the function fails, the return value is an error value.
--*/
{
DWORD Status;
DWORD Length;
PCNODE Node = (PCNODE)hNode;
LPWSTR Guid=NULL;
if (Node == NULL) {
return(GetCurrentClusterNodeId(lpszNodeId, lpcchName));
}
WRAP(Status,
(ApiGetNodeId(Node->hNode,
&Guid)),
Node->Cluster);
if (Status != ERROR_SUCCESS) {
return(Status);
}
MylstrcpynW(lpszNodeId, Guid, *lpcchName);
Length = lstrlenW(Guid);
if (Length >= *lpcchName) {
if (lpszNodeId == NULL) {
Status = ERROR_SUCCESS;
} else {
Status = ERROR_MORE_DATA;
}
}
*lpcchName = Length;
MIDL_user_free(Guid);
return(Status);
}
CLUSTER_NODE_STATE
WINAPI
GetClusterNodeState(
IN HNODE hNode
)
/*++
Routine Description:
Returns the current state of a cluster node.
Arguments:
hNode - Supplies the cluster node whose current state is to be returned
Return Value:
The current state of the cluster node. Currently defined node states
include:
ClusterNodeUp
ClusterNodeDown
ClusterNodePaused
--*/
{
DWORD Status;
CLUSTER_NODE_STATE State;
PCNODE Node = (PCNODE)hNode;
WRAP(Status,
(ApiGetNodeState(Node->hNode, (LPDWORD)&State)),
Node->Cluster);
if (Status == ERROR_SUCCESS) {
return(State);
} else {
SetLastError(Status);
return(ClusterNodeStateUnknown);
}
}
DWORD
WINAPI
PauseClusterNode(
IN HNODE hNode
)
/*++
Routine Description:
Requests that a node pauses its cluster activity.
Arguments:
hNode - Supplies a handle to the node to leave its cluster.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD Status;
PCNODE Node = (PCNODE)hNode;
WRAP(Status,
(ApiPauseNode(Node->hNode)),
Node->Cluster);
return(Status);
}
DWORD
WINAPI
ResumeClusterNode(
IN HNODE hNode
)
/*++
Routine Description:
Requests that a node resume cluster activity, after it had been paused.
Arguments:
hNode - Supplies a handle to the node to resume its cluster activity.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD Status;
PCNODE Node = (PCNODE)hNode;
WRAP(Status,
(ApiResumeNode(Node->hNode)),
Node->Cluster);
return(Status);
}
DWORD
WINAPI
EvictClusterNode(
IN HNODE hNode
)
/*++
Routine Description:
Evict the specified Node from the list of nodes in the permanent cluster
database (registry).
Arguments:
hNode - Supplies a handle to the node to remove from the list of cluster
nodes.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/
{
DWORD Status;
PCNODE Node = (PCNODE)hNode;
WRAP(Status,
(ApiEvictNode(Node->hNode)),
Node->Cluster);
return(Status);
}
DWORD
WINAPI
EvictClusterNodeEx(
IN HNODE hNode,
IN DWORD dwTimeout,
OUT HRESULT* phrCleanupStatus
)
/*++
Routine Description:
Evict the specified node from the list of nodes in the permanent cluster
database (registry) and initate the cleanup(unconfiguration) process on the
cluster node. Note that if the node is down, the clean up process will not
occur. However, when the node comes up, clustering will detect that the
node was supposed to be evicted and it will unconfigure itself.
Arguments:
IN HNODE hNode - Supplies a handle to the node to remove from the list of cluster
nodes.
IN DWORD dwTimeOut - Timeout in milliseconds for the cleanup(unconfiguration
of clustering) to complete. If the cleanup doesnt complete
in the given amount of time, the function will return.
OUT phrCleanupStatus - The status of cleanup is returned.
Return Value:
Returns the status of the eviction and not of cleanup.
ERROR_SUCCESS if successful
ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP if eviction succeeded but cleanup returned
an error. The phrCleanupStatus param will contain more information about
the cleanup error. (Usually this will be RPC_S_CALL_FAILED.)
Win32 error code otherwise
--*/
{
DWORD Status;
PCNODE Node = (PCNODE)hNode;
HRESULT hr = E_ABORT;
WRAP(Status,
(ApiEvictNode(Node->hNode)),
Node->Cluster);
if (Status != ERROR_SUCCESS) {
goto FnExit;
}
//
// Any error after this is not "fatal". The node has been evicted
// but the cleanup may fail for numerous reasons.
//
hr = ClRtlAsyncCleanupNode(Node->Name, 0, dwTimeout);
if (FAILED(hr)) {
Status = ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP;
}
FnExit:
if (phrCleanupStatus != NULL) {
*phrCleanupStatus = hr;
}
return(Status);
} // EvictClusterNodeEx()
HCLUSTER
WINAPI
GetClusterFromNode(
IN HNODE hNode
)
/*++
Routine Description:
Returns the cluster handle from the associated node handle.
Arguments:
hNode - Supplies the node.
Return Value:
Handle to the cluster associated with the node handle.
--*/
{
DWORD nStatus;
PCNODE Node = (PCNODE)hNode;
HCLUSTER hCluster = (HCLUSTER)Node->Cluster;
nStatus = AddRefToClusterHandle( hCluster );
if ( nStatus != ERROR_SUCCESS ) {
SetLastError( nStatus );
hCluster = NULL;
}
return( hCluster );
} // GetClusterFromNode()