client.c

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

C
579
字号
/* $Id: client.c 21257 2006-03-08 23:07:09Z audit $
 *
 * client.c - Session Manager client Management
 * 
 * ReactOS Operating System
 * 
 * --------------------------------------------------------------------
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.LIB. If not, write
 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.  
 *
 * --------------------------------------------------------------------
 */
#include "smss.h"
#include <sm/helper.h>

#define NDEBUG
#include <debug.h>

/* Private ADT */

#define SM_MAX_CLIENT_COUNT 16
#define SM_INVALID_CLIENT_INDEX -1

struct _SM_CLIENT_DIRECTORY
{
	RTL_CRITICAL_SECTION  Lock;
	ULONG                 Count;
	PSM_CLIENT_DATA       Client [SM_MAX_CLIENT_COUNT];
	PSM_CLIENT_DATA       CandidateClient;

} SmpClientDirectory;


/**********************************************************************
 *	SmInitializeClientManagement/0
 */
NTSTATUS
SmInitializeClientManagement (VOID)
{
	DPRINT("SM: %s called\n", __FUNCTION__);
	RtlInitializeCriticalSection(& SmpClientDirectory.Lock);
	SmpClientDirectory.Count = 0;
	RtlZeroMemory (SmpClientDirectory.Client, sizeof SmpClientDirectory.Client);
	SmpClientDirectory.CandidateClient = NULL;
	return STATUS_SUCCESS;

}
/**********************************************************************
 * SmpSetClientInitialized/1
 */
VOID FASTCALL
SmpSetClientInitialized (PSM_CLIENT_DATA Client)
{
	DPRINT("SM: %s(%08lx) called\n", __FUNCTION__, Client);
	Client->Flags |= SM_CLIENT_FLAG_INITIALIZED;
}
/**********************************************************************
 * SmpGetFirstFreeClientEntry/0					PRIVATE
 *
 * NOTE: call it holding SmpClientDirectory.Lock only
 */
static INT STDCALL SmpGetFirstFreeClientEntry (VOID)
{
	INT ClientIndex = 0;

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

	if (SmpClientDirectory.Count < SM_MAX_CLIENT_COUNT)
	{
		for (ClientIndex = 0;
			(ClientIndex < SM_MAX_CLIENT_COUNT);
			ClientIndex ++)
		{
			if (NULL == SmpClientDirectory.Client[ClientIndex])
			{
				DPRINT("SM: %s => %d\n", __FUNCTION__, ClientIndex);
				return ClientIndex; // found
			}
		}
	}
	return SM_INVALID_CLIENT_INDEX; // full!		
}
/**********************************************************************
 *	SmpLookupClient/1					PRIVATE
 *
 * DESCRIPTION
 * 	Lookup the subsystem server descriptor (client data) given its
 * 	base image ID.
 *
 * ARGUMENTS
 *	SubsystemId: IMAGE_SUBSYSTEM_xxx
 *
 * RETURN VALUES
 *	SM_INVALID_CLIENT_INDEX on error;
 *	otherwise an index in the range (0..SM_MAX_CLIENT_COUNT).
 *
 * WARNING
 * 	SmpClientDirectory.Lock must be held by the caller.
 */
static INT FASTCALL
SmpLookupClient (USHORT SubsystemId)
{
	INT  ClientIndex = 0;

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

	if (0 != SmpClientDirectory.Count)
	{
		for (ClientIndex = 0; (ClientIndex < SM_MAX_CLIENT_COUNT); ClientIndex ++)
		{
			if (NULL != SmpClientDirectory.Client[ClientIndex])
			{
				if (SubsystemId == SmpClientDirectory.Client[ClientIndex]->SubsystemId)
				{
					return ClientIndex;
				}
			}
		}
	}	
	return SM_INVALID_CLIENT_INDEX;
}
/**********************************************************************
 * 	SmpDestroyClientObject/2				PRIVATE
 *
 * WARNING
 * 	SmpClientDirectory.Lock must be held by the caller.
 */
static NTSTATUS STDCALL
SmpDestroyClientObject (PSM_CLIENT_DATA Client, NTSTATUS DestroyReason)
{
	DPRINT("SM:%s(%08lx,%08lx) called\n", __FUNCTION__, DestroyReason);
	/* TODO: send shutdown to the SB port */
	NtTerminateProcess (Client->ServerProcess, DestroyReason);
	RtlFreeHeap (SmpHeap, 0, Client);
	-- SmpClientDirectory.Count;
	return STATUS_SUCCESS;
}
/**********************************************************************
 * 	SmBeginClientInitialization/1
 *
 * DESCRIPTION
 * 	Check if the candidate client matches the begin session
 * 	message from the subsystem process.
 *
 * ARGUMENTS
 *	Request: message received by \SmApiPort
 *	ClientData:
 *		
 * RETURN VALUES
 *	NTSTATUS
 */
NTSTATUS STDCALL
SmBeginClientInitialization (IN  PSM_PORT_MESSAGE Request,
			     OUT PSM_CLIENT_DATA  * ClientData)
{
	NTSTATUS          Status = STATUS_SUCCESS;
	PSM_CONNECT_DATA  ConnectData = SmpGetConnectData (Request);
	ULONG             SbApiPortNameSize = SM_CONNECT_DATA_SIZE(*Request);
	INT               ClientIndex = SM_INVALID_CLIENT_INDEX;


	DPRINT("SM: %s(%08lx,%08lx) called\n", __FUNCTION__,
			Request, ClientData);
	
	RtlEnterCriticalSection (& SmpClientDirectory.Lock);
	/*
	 * Is there a subsystem bootstrap in progress?
	 */
	if (NULL != SmpClientDirectory.CandidateClient)
	{
		PROCESS_BASIC_INFORMATION pbi;
		
		RtlZeroMemory (& pbi, sizeof pbi);
		Status = NtQueryInformationProcess (Request->Header.ClientId.UniqueProcess,
					    	    ProcessBasicInformation,
						    & pbi,
						    sizeof pbi,
						    NULL);
		if (NT_SUCCESS(Status))
		{
			SmpClientDirectory.CandidateClient->ServerProcessId =
				(ULONG) pbi.UniqueProcessId;
		}
	}
	else
	{
		DPRINT1("SM: %s: subsys booting with no descriptor!\n", __FUNCTION__);
		Status = STATUS_NOT_FOUND;
		RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
		return Status;		
	}
	/*
	 * Check if a client for the ID already exist.
	 */
	if (SM_INVALID_CLIENT_INDEX != SmpLookupClient(ConnectData->SubSystemId))
	{
		DPRINT("SM: %s: attempt to register again subsystem %d.\n",
			__FUNCTION__,
			ConnectData->SubSystemId);
		// TODO something else to do here?
		RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
		return STATUS_UNSUCCESSFUL;
	}
	/*
	 * Check if a free entry exists in SmpClientDirectory.Client[].
	 */
	ClientIndex = SmpGetFirstFreeClientEntry();
	if (SM_INVALID_CLIENT_INDEX == ClientIndex)
	{
		DPRINT("SM: %s: SM_INVALID_CLIENT_INDEX == ClientIndex ", __FUNCTION__);
		SmpDestroyClientObject (SmpClientDirectory.CandidateClient, STATUS_NO_MEMORY);
		SmpClientDirectory.CandidateClient = NULL;
		return STATUS_NO_MEMORY;
	}

	/* OK! */
	DPRINT("SM: %s: registering subsystem ID=%d \n",
		__FUNCTION__, ConnectData->SubSystemId);

	/*
	 * Initialize the client data
	 */
	SmpClientDirectory.CandidateClient->SubsystemId = ConnectData->SubSystemId;
	/* SM && DBG auto-initializes; other subsystems are required to call
	 * SM_API_COMPLETE_SESSION via SMDLL. */
	if ((IMAGE_SUBSYSTEM_NATIVE == SmpClientDirectory.CandidateClient->SubsystemId) ||
	    ((USHORT)-1 == SmpClientDirectory.CandidateClient->SubsystemId))
	{
		SmpSetClientInitialized (SmpClientDirectory.CandidateClient);
	}
	if (SbApiPortNameSize > 0)
	{
		/* Only external servers have an SB port */
		RtlCopyMemory (SmpClientDirectory.CandidateClient->SbApiPortName,
			       ConnectData->SbName,
			       SbApiPortNameSize);
	}
	/*
	 * Insert the new descriptor in the
	 * client directory.
	 */
	SmpClientDirectory.Client [ClientIndex] = SmpClientDirectory.CandidateClient;
	/*
	 * Increment the number of active subsystems.
	 */
	++ SmpClientDirectory.Count;
	/*
	 * Notify to the caller the reference to the client data.
	 */
	if (ClientData) 
	{
		*ClientData = SmpClientDirectory.CandidateClient;
	}
	/*
	 * Free the slot for the candidate subsystem.
	 */
	SmpClientDirectory.CandidateClient = NULL;

	/* Done */
	RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
	
	return STATUS_SUCCESS;
}
/**********************************************************************
 *	SmCompleteClientInitialization/1
 *
 * DESCRIPTION
 * 	Lookup the subsystem server descriptor given the process ID
 * 	of the subsystem server process.
 */
NTSTATUS STDCALL
SmCompleteClientInitialization (ULONG ProcessId)
{
	NTSTATUS  Status = STATUS_NOT_FOUND;
	INT       ClientIndex = SM_INVALID_CLIENT_INDEX;

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

⌨️ 快捷键说明

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