client.c

来自「一个类似windows」· C语言 代码 · 共 579 行 · 第 1/2 页

C
579
字号

	RtlEnterCriticalSection (& SmpClientDirectory.Lock);
	if (SmpClientDirectory.Count > 0)
	{
		for (ClientIndex = 0; ClientIndex < SM_MAX_CLIENT_COUNT; ClientIndex ++)
		{		
			if ((NULL != SmpClientDirectory.Client [ClientIndex]) &&
				(ProcessId == SmpClientDirectory.Client [ClientIndex]->ServerProcessId))
			{
				SmpSetClientInitialized (SmpClientDirectory.Client [ClientIndex]);
				Status = STATUS_SUCCESS;
				break;
			}
		}
	}
	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	return Status;
}
/**********************************************************************
 * 	SmpDestroyClientByClientIndex/1				PRIVATE
 */
static NTSTATUS STDCALL
SmpDestroyClientByClientIndex (INT ClientIndex)
{
	NTSTATUS         Status = STATUS_SUCCESS;
	PSM_CLIENT_DATA  Client = NULL;

	DPRINT("SM: %s(%d) called\n", __FUNCTION__, ClientIndex);

	if (SM_INVALID_CLIENT_INDEX == ClientIndex)
	{
		DPRINT1("SM: %s: SM_INVALID_CLIENT_INDEX == ClientIndex!\n",
			__FUNCTION__);
		Status = STATUS_NOT_FOUND;
	}
	else
	{
		Client = SmpClientDirectory.Client [ClientIndex];
		SmpClientDirectory.Client [ClientIndex] = NULL;
		if (NULL != Client)
		{
			Status = SmpDestroyClientObject (Client, STATUS_SUCCESS);
		} else {
			DPRINT("SM:%s: NULL == Client[%d]!\n", __FUNCTION__,
				ClientIndex);
			Status = STATUS_UNSUCCESSFUL;
		}
	}
	return Status;
}
/**********************************************************************
 *	SmpTimeoutCandidateClient/1
 *
 * DESCRIPTION
 * 	Give the candidate client time to bootstrap and complete
 * 	session initialization. If the client fails in any way,
 * 	drop the pending client and kill the process.
 *
 * ARGUMENTS
 * 	x: HANDLE for the candidate process.
 *
 * RETURN VALUE
 * 	NONE.
 */
static VOID STDCALL SmpTimeoutCandidateClient (PVOID x)
{
	NTSTATUS       Status = STATUS_SUCCESS;
	HANDLE         CandidateClientProcessHandle = (HANDLE) x;
	LARGE_INTEGER  TimeOut;

	DPRINT("SM: %s(%lx) called\n", __FUNCTION__, x);

	TimeOut.QuadPart = (LONGLONG) -300000000L; // 30s
	Status = NtWaitForSingleObject (CandidateClientProcessHandle,
					FALSE,
					& TimeOut);
	if (STATUS_TIMEOUT == Status)
	{
		RtlEnterCriticalSection (& SmpClientDirectory.Lock);
		if (NULL != SmpClientDirectory.CandidateClient)
		{
			DPRINT("SM:%s: destroy candidate %08lx\n", __FUNCTION__,
					SmpClientDirectory.CandidateClient);
			Status = SmpDestroyClientObject (SmpClientDirectory.CandidateClient,
							 STATUS_TIMEOUT);
			SmpClientDirectory.CandidateClient = NULL;
		}
		RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	}
	NtTerminateThread (NtCurrentThread(), Status);
}
/**********************************************************************
 *	SmpCreateClient/1
 *
 * DESCRIPTION
 * 	Create a "candidate" client. Client descriptor will enter the
 * 	client directory only at the end of the registration
 * 	procedure. Otherwise, we will kill the associated process.
 *
 * ARGUMENTS
 * 	ProcessHandle: handle of the subsystem server process.
 *
 * RETURN VALUE
 * 	NTSTATUS:
 * 		STATUS_SUCCESS if all OK;
 * 		STATUS_DEVICE_BUSY if another SS is still booting;
 * 		STATUS_NO_MEMORY if client descriptor allocation failed;
 * 		
 * 		
 */
NTSTATUS STDCALL
SmCreateClient (PRTL_USER_PROCESS_INFORMATION ProcessInfo, PWSTR ProgramName)
{
	NTSTATUS Status = STATUS_SUCCESS;
	
	DPRINT("SM: %s(%lx, %S) called\n", __FUNCTION__, ProcessInfo->ProcessHandle, ProgramName);

	RtlEnterCriticalSection (& SmpClientDirectory.Lock);
	/*
	 * Check if the candidate client slot is empty.
	 */
	if (NULL == SmpClientDirectory.CandidateClient)
	{
		/*
		 * Check if there exist a free entry in the
		 * SmpClientDirectory.Client array.
		 */
		if (SM_INVALID_CLIENT_INDEX == SmpGetFirstFreeClientEntry())
		{
			DPRINT("SM: %s(%lx): out of memory!\n",
				__FUNCTION__, ProcessInfo->ProcessHandle);
			Status = STATUS_NO_MEMORY;
		}
		/*
		 * Allocate the storage for client data
		 */
		SmpClientDirectory.CandidateClient =
			RtlAllocateHeap (SmpHeap,
					 HEAP_ZERO_MEMORY,
					 sizeof (SM_CLIENT_DATA));
		if (NULL == SmpClientDirectory.CandidateClient)
		{
			DPRINT("SM: %s(%lx): out of memory!\n",
				__FUNCTION__, ProcessInfo->ProcessHandle);
			Status = STATUS_NO_MEMORY;
		}
		else
		{
			DPRINT("SM:%s(%08lx,%S): candidate is %08lx\n", __FUNCTION__,
					ProcessInfo, ProgramName, SmpClientDirectory.CandidateClient);
			/* Initialize the candidate client. */
			RtlInitializeCriticalSection(& SmpClientDirectory.CandidateClient->Lock);
			SmpClientDirectory.CandidateClient->ServerProcess =
				(HANDLE) ProcessInfo->ProcessHandle;
			SmpClientDirectory.CandidateClient->ServerProcessId = 
				(ULONG) ProcessInfo->ClientId.UniqueProcess;
			/*
			 * Copy the program name
			 */
			RtlCopyMemory (SmpClientDirectory.CandidateClient->ProgramName,
				       ProgramName,
				       SM_SB_NAME_MAX_LENGTH);
		}
	} else {
		DPRINT1("SM: %s: CandidateClient %08lx pending!\n", __FUNCTION__,
				SmpClientDirectory.CandidateClient);
		Status = STATUS_DEVICE_BUSY;
	}

	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);

	/* Create the timeout thread for external subsystems */
	if (_wcsicmp (ProgramName, L"Session Manager") && _wcsicmp (ProgramName, L"Debug"))
	{
		Status = RtlCreateUserThread (NtCurrentProcess(),
						NULL,
						FALSE,
						0,
						0,
						0,
						(PTHREAD_START_ROUTINE) SmpTimeoutCandidateClient,
						SmpClientDirectory.CandidateClient->ServerProcess,
						NULL,
						NULL);
		if (!NT_SUCCESS(Status))
		{
			DPRINT1("SM:%s: RtlCreateUserThread() failed (Status=%08lx)\n",
				__FUNCTION__, Status);
		}
	}

	return Status;
}
/**********************************************************************
 * 	SmpDestroyClient/1
 *
 * 	1. close any handle
 * 	2. kill client process
 * 	3. release resources
 */
NTSTATUS STDCALL
SmDestroyClient (ULONG SubsystemId)
{
	NTSTATUS  Status = STATUS_SUCCESS;
	INT       ClientIndex = SM_INVALID_CLIENT_INDEX;

	DPRINT("SM: %s(%lu) called\n", __FUNCTION__, SubsystemId);

	RtlEnterCriticalSection (& SmpClientDirectory.Lock);
	ClientIndex = SmpLookupClient (SubsystemId);
	if (SM_INVALID_CLIENT_INDEX == ClientIndex)
	{
		DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n",
			__FUNCTION__, SubsystemId);
		return STATUS_NOT_FOUND;
	}
	Status = SmpDestroyClientByClientIndex (ClientIndex);
	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	return Status;
}

/* === Utilities for SmQryInfo === */

/**********************************************************************
 * SmGetClientBasicInformation/1
 */
NTSTATUS FASTCALL
SmGetClientBasicInformation (PSM_BASIC_INFORMATION i)
{
	INT  ClientIndex = 0;
	INT  Index = 0;

	DPRINT("SM: %s(%08lx) called\n", __FUNCTION__, i);

	RtlEnterCriticalSection (& SmpClientDirectory.Lock);

	i->SubSystemCount = SmpClientDirectory.Count;
	i->Unused = 0;
	
	if (SmpClientDirectory.Count > 0)
	{
		for (ClientIndex = 0; (ClientIndex < SM_MAX_CLIENT_COUNT); ClientIndex ++)
		{
			if ((NULL != SmpClientDirectory.Client [ClientIndex]) &&
				(Index < SM_QRYINFO_MAX_SS_COUNT))
			{
				i->SubSystem[Index].Id        = SmpClientDirectory.Client [ClientIndex]->SubsystemId;
				i->SubSystem[Index].Flags     = SmpClientDirectory.Client [ClientIndex]->Flags;
				i->SubSystem[Index].ProcessId = SmpClientDirectory.Client [ClientIndex]->ServerProcessId;
				++ Index;
			}
		}
	}

	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	return STATUS_SUCCESS;
}

/**********************************************************************
 * SmGetSubSystemInformation/1
 */
NTSTATUS FASTCALL
SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i)
{
	NTSTATUS  Status = STATUS_SUCCESS;
	INT       ClientIndex = SM_INVALID_CLIENT_INDEX;
	
	DPRINT("SM: %s(%08lx) called\n", __FUNCTION__, i);

	RtlEnterCriticalSection (& SmpClientDirectory.Lock);
	ClientIndex = SmpLookupClient (i->SubSystemId);
	if (SM_INVALID_CLIENT_INDEX == ClientIndex)
	{
		Status = STATUS_NOT_FOUND;
	}
	else
	{
		i->Flags     = SmpClientDirectory.Client [ClientIndex]->Flags;
		i->ProcessId = SmpClientDirectory.Client [ClientIndex]->ServerProcessId;
		RtlCopyMemory (i->NameSpaceRootNode,
				SmpClientDirectory.Client [ClientIndex]->SbApiPortName,
				(SM_QRYINFO_MAX_ROOT_NODE * sizeof(i->NameSpaceRootNode[0])));
	}
	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	return Status;
}

/* EOF */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?