Author: ekohl Date: Sun Jul 17 15:45:03 2011 New Revision: 52717
URL: http://svn.reactos.org/svn/reactos?rev=52717&view=rev Log: [SERVICES] Implement service image records. This will enable us to run executables that contain multiple services and control them individually.
Modified: trunk/reactos/base/system/services/database.c trunk/reactos/base/system/services/rpcserver.c trunk/reactos/base/system/services/services.h
Modified: trunk/reactos/base/system/services/database.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/databa... ============================================================================== --- trunk/reactos/base/system/services/database.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/database.c [iso-8859-1] Sun Jul 17 15:45:03 2011 @@ -25,6 +25,7 @@
/* GLOBALS *******************************************************************/
+LIST_ENTRY ImageListHead; LIST_ENTRY ServiceListHead;
static RTL_RESOURCE DatabaseLock; @@ -33,6 +34,227 @@ static CRITICAL_SECTION ControlServiceCriticalSection;
/* FUNCTIONS *****************************************************************/ + +static DWORD +ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage) +{ + WCHAR szControlPipeName[MAX_PATH + 1]; + HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; + DWORD ServiceCurrent = 0; + DWORD KeyDisposition; + DWORD dwKeySize; + DWORD dwError; + + /* Get the service number */ + /* TODO: Create registry entry with correct write access */ + dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\CurrentControlSet\Control\ServiceCurrent", 0, NULL, + REG_OPTION_VOLATILE, + KEY_WRITE | KEY_READ, + NULL, + &hServiceCurrentKey, + &KeyDisposition); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError); + return dwError; + } + + if (KeyDisposition == REG_OPENED_EXISTING_KEY) + { + dwKeySize = sizeof(DWORD); + dwError = RegQueryValueExW(hServiceCurrentKey, + L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize); + + if (dwError != ERROR_SUCCESS) + { + RegCloseKey(hServiceCurrentKey); + DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); + return dwError; + } + + ServiceCurrent++; + } + + dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); + + RegCloseKey(hServiceCurrentKey); + + if (dwError != ERROR_SUCCESS) + { + DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); + return dwError; + } + + /* Create '\.\pipe\net\NtControlPipeXXX' instance */ + swprintf(szControlPipeName, L"\\.\pipe\net\NtControlPipe%u", ServiceCurrent); + + DPRINT("PipeName: %S\n", szControlPipeName); + + pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 100, + 8000, + 4, + 30000, + NULL); + DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); + if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) + { + DPRINT1("Failed to create control pipe!\n"); + return GetLastError(); + } + + return ERROR_SUCCESS; +} + + +static PSERVICE_IMAGE +ScmGetServiceImageByImagePath(LPWSTR lpImagePath) +{ + PLIST_ENTRY ImageEntry; + PSERVICE_IMAGE CurrentImage; + + DPRINT("ScmGetServiceImageByImagePath() called\n"); + + ImageEntry = ImageListHead.Flink; + while (ImageEntry != &ImageListHead) + { + CurrentImage = CONTAINING_RECORD(ImageEntry, + SERVICE_IMAGE, + ImageListEntry); + if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0) + { + DPRINT("Found image: '%S'\n", CurrentImage->szImagePath); + return CurrentImage; + } + + ImageEntry = ImageEntry->Flink; + } + + DPRINT1("Couldn't find a matching image\n"); + + return NULL; + +} + + +static DWORD +ScmCreateOrReferenceServiceImage(PSERVICE pService) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + UNICODE_STRING ImagePath; + PSERVICE_IMAGE pServiceImage = NULL; + NTSTATUS Status; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("ScmCreateOrReferenceServiceImage()"); + + RtlInitUnicodeString(&ImagePath, NULL); + + /* Get service data */ + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"ImagePath"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].EntryContext = &ImagePath; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, + pService->lpServiceName, + QueryTable, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); + return RtlNtStatusToDosError(Status); + } + + DPRINT("ImagePath: '%wZ'\n", &ImagePath); + + pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); + if (pServiceImage == NULL) + { + /* Create a new service image */ + pServiceImage = (PSERVICE_IMAGE)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SERVICE_IMAGE) + ((wcslen(ImagePath.Buffer) + 1) * sizeof(WCHAR))); + if (pServiceImage == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + pServiceImage->dwImageRunCount = 1; + pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; + pServiceImage->hProcess = INVALID_HANDLE_VALUE; + + /* Set the image path */ + wcscpy(pServiceImage->szImagePath, + ImagePath.Buffer); + + RtlFreeUnicodeString(&ImagePath); + + /* Create the control pipe */ + dwError = ScmCreateNewControlPipe(pServiceImage); + if (dwError != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, pServiceImage); + goto done; + } + + /* FIXME: Add more initialization code here */ + + + /* Append service record */ + InsertTailList(&ImageListHead, + &pServiceImage->ImageListEntry); + + pService->lpImage = pServiceImage; + } + else + { + /* Create a new service image */ + pService->lpImage->dwImageRunCount++; + } + +done:; + RtlFreeUnicodeString(&ImagePath); + + return dwError; +} + + +static VOID +ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage) +{ + DPRINT1("ScmDereferenceServiceImage() called\n"); + + pServiceImage->dwImageRunCount--; + + if (pServiceImage->dwImageRunCount == 0) + { + DPRINT1("dwImageRunCount == 0\n"); + + /* FIXME: Terminate the process */ + + /* Remove the service image from the list */ + RemoveEntryList(&pServiceImage->ImageListEntry); + + /* Close the control pipe */ + if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) + CloseHandle(pServiceImage->hControlPipe); + + /* Close the process handle */ + if (pServiceImage->hProcess != INVALID_HANDLE_VALUE) + CloseHandle(pServiceImage->hProcess); + + /* Release the service image */ + HeapFree(GetProcessHeap(), 0, pServiceImage); + } +}
PSERVICE @@ -131,7 +353,7 @@ DPRINT("Service: '%S'\n", lpServiceName);
/* Allocate service entry */ - lpService = (SERVICE*) HeapAlloc(GetProcessHeap(), + lpService = (SERVICE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR))); if (lpService == NULL) @@ -173,9 +395,9 @@ lpService->lpDisplayName != lpService->lpServiceName) HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
- /* Decrement the image reference counter */ + /* Dereference the service image */ if (lpService->lpImage) - lpService->lpImage->dwServiceRefCount--; + ScmDereferenceServiceImage(lpService->lpImage);
/* Decrement the group reference counter */ if (lpService->lpGroup) @@ -183,9 +405,6 @@
/* FIXME: SecurityDescriptor */
- /* Close the control pipe */ - if (lpService->ControlPipeHandle != INVALID_HANDLE_VALUE) - CloseHandle(lpService->ControlPipeHandle);
/* Remove the Service from the List */ RemoveEntryList(&lpService->ServiceListEntry); @@ -329,6 +548,12 @@
if (lpDisplayName != NULL) HeapFree(GetProcessHeap(), 0, lpDisplayName); + + if (lpService != NULL) + { + if (lpService->lpImage != NULL) + ScmDereferenceServiceImage(lpService->lpImage); + }
return dwError; } @@ -479,6 +704,7 @@ return dwError;
/* Initialize basic variables */ + InitializeListHead(&ImageListHead); InitializeListHead(&ServiceListHead);
/* Initialize the database lock */ @@ -711,14 +937,14 @@ wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
/* Send the control packet */ - WriteFile(Service->ControlPipeHandle, + WriteFile(Service->lpImage->hControlPipe, ControlPacket, sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)), &dwWriteCount, NULL);
/* Read the reply */ - ReadFile(Service->ControlPipeHandle, + ReadFile(Service->lpImage->hControlPipe, &ReplyPacket, sizeof(SCM_REPLY_PACKET), &dwReadCount, @@ -732,6 +958,12 @@ if (dwReadCount == sizeof(SCM_REPLY_PACKET)) { dwError = ReplyPacket.dwError; + } + + if (dwError == ERROR_SUCCESS && + dwControl == SERVICE_CONTROL_STOP) + { + ScmDereferenceServiceImage(Service->lpImage); }
LeaveCriticalSection(&ControlServiceCriticalSection); @@ -804,14 +1036,14 @@ *Ptr = 0;
/* Send the start command */ - WriteFile(Service->ControlPipeHandle, + WriteFile(Service->lpImage->hControlPipe, ControlPacket, sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR), &dwWriteCount, NULL);
/* Read the reply */ - ReadFile(Service->ControlPipeHandle, + ReadFile(Service->lpImage->hControlPipe, &ReplyPacket, sizeof(SCM_REPLY_PACKET), &dwReadCount, @@ -838,107 +1070,11 @@ DWORD argc, LPWSTR *argv) { - RTL_QUERY_REGISTRY_TABLE QueryTable[3]; PROCESS_INFORMATION ProcessInformation; STARTUPINFOW StartupInfo; - UNICODE_STRING ImagePath; - ULONG Type; - DWORD ServiceCurrent = 0; BOOL Result; - NTSTATUS Status; DWORD dwError = ERROR_SUCCESS; - WCHAR NtControlPipeName[MAX_PATH + 1]; - HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; - DWORD KeyDisposition; DWORD dwProcessId; - - RtlInitUnicodeString(&ImagePath, NULL); - - /* Get service data */ - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"Type"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].EntryContext = &Type; - - QueryTable[1].Name = L"ImagePath"; - QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[1].EntryContext = &ImagePath; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, - Service->lpServiceName, - QueryTable, - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); - return RtlNtStatusToDosError(Status); - } - DPRINT("ImagePath: '%S'\n", ImagePath.Buffer); - DPRINT("Type: %lx\n", Type); - - /* Get the service number */ - /* TODO: Create registry entry with correct write access */ - Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\CurrentControlSet\Control\ServiceCurrent", 0, NULL, - REG_OPTION_VOLATILE, - KEY_WRITE | KEY_READ, - NULL, - &hServiceCurrentKey, - &KeyDisposition); - - if (ERROR_SUCCESS != Status) - { - DPRINT1("RegCreateKeyEx() failed with status %u\n", Status); - return Status; - } - - if (REG_OPENED_EXISTING_KEY == KeyDisposition) - { - DWORD KeySize = sizeof(ServiceCurrent); - Status = RegQueryValueExW(hServiceCurrentKey, L"", 0, NULL, (BYTE*)&ServiceCurrent, &KeySize); - - if (ERROR_SUCCESS != Status) - { - RegCloseKey(hServiceCurrentKey); - DPRINT1("RegQueryValueEx() failed with status %u\n", Status); - return Status; - } - - ServiceCurrent++; - } - - Status = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); - - RegCloseKey(hServiceCurrentKey); - - if (ERROR_SUCCESS != Status) - { - DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status); - return Status; - } - - /* Create '\.\pipe\net\NtControlPipeXXX' instance */ - swprintf(NtControlPipeName, L"\\.\pipe\net\NtControlPipe%u", ServiceCurrent); - - DPRINT("Service: %p ImagePath: %wZ PipeName: %S\n", Service, &ImagePath, NtControlPipeName); - - Service->ControlPipeHandle = CreateNamedPipeW(NtControlPipeName, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - 100, - 8000, - 4, - 30000, - NULL); - DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName); - if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE) - { - DPRINT1("Failed to create control pipe!\n"); - return GetLastError(); - }
StartupInfo.cb = sizeof(StartupInfo); StartupInfo.lpReserved = NULL; @@ -949,7 +1085,7 @@ StartupInfo.lpReserved2 = 0;
Result = CreateProcessW(NULL, - ImagePath.Buffer, + Service->lpImage->szImagePath, NULL, NULL, FALSE, @@ -958,15 +1094,9 @@ NULL, &StartupInfo, &ProcessInformation); - RtlFreeUnicodeString(&ImagePath); - if (!Result) { dwError = GetLastError(); - /* Close control pipe */ - CloseHandle(Service->ControlPipeHandle); - Service->ControlPipeHandle = INVALID_HANDLE_VALUE; - DPRINT1("Starting '%S' failed!\n", Service->lpServiceName); return dwError; } @@ -978,15 +1108,15 @@ ProcessInformation.dwThreadId, ProcessInformation.hThread);
- /* Get process and thread ids */ - Service->ProcessId = ProcessInformation.dwProcessId; - Service->ThreadId = ProcessInformation.dwThreadId; + /* Get process handle and id */ + Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; + Service->lpImage->hProcess = ProcessInformation.hProcess;
/* Resume Thread */ ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */ - if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ? + if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ? TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED) { DWORD dwRead = 0; @@ -994,7 +1124,7 @@ DPRINT("Control pipe connected!\n");
/* Read SERVICE_STATUS_HANDLE from pipe */ - if (!ReadFile(Service->ControlPipeHandle, + if (!ReadFile(Service->lpImage->hControlPipe, (LPVOID)&dwProcessId, sizeof(DWORD), &dwRead, @@ -1015,17 +1145,10 @@ else { DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); - - /* Close control pipe */ - CloseHandle(Service->ControlPipeHandle); - Service->ControlPipeHandle = INVALID_HANDLE_VALUE; - Service->ProcessId = 0; - Service->ThreadId = 0; - } - - /* Close process and thread handle */ + } + + /* Close thread handle */ CloseHandle(ProcessInformation.hThread); - CloseHandle(ProcessInformation.hProcess);
return dwError; } @@ -1051,7 +1174,6 @@ return ERROR_SERVICE_ALREADY_RUNNING; }
- Service->ControlPipeHandle = INVALID_HANDLE_VALUE; DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
if (Service->Status.dwServiceType & SERVICE_DRIVER) @@ -1067,14 +1189,23 @@ else { /* Start user-mode service */ - dwError = ScmStartUserModeService(Service, argc, argv); + dwError = ScmCreateOrReferenceServiceImage(Service); if (dwError == ERROR_SUCCESS) { + dwError = ScmStartUserModeService(Service, argc, argv); + if (dwError == ERROR_SUCCESS) + { #ifdef USE_SERVICE_START_PENDING - Service->Status.dwCurrentState = SERVICE_START_PENDING; + Service->Status.dwCurrentState = SERVICE_START_PENDING; #else - Service->Status.dwCurrentState = SERVICE_RUNNING; + Service->Status.dwCurrentState = SERVICE_RUNNING; #endif + } + else + { + ScmDereferenceServiceImage(Service->lpImage); + Service->lpImage = NULL; + } } }
Modified: trunk/reactos/base/system/services/rpcserver.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/rpcser... ============================================================================== --- trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] Sun Jul 17 15:45:03 2011 @@ -722,15 +722,6 @@
if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded)) dwError = ERROR_DEPENDENT_SERVICES_RUNNING; - - if (dwError == ERROR_SUCCESS && - dwControl == SERVICE_CONTROL_STOP && - lpServiceStatus->dwCurrentState == SERVICE_STOPPED) - { - lpService->ProcessId = 0; /* FIXME */ - lpService->ThreadId = 0; - } -
return dwError; } @@ -4897,7 +4888,7 @@ &lpService->Status, sizeof(SERVICE_STATUS));
- lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */ + lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */ lpStatus->dwServiceFlags = 0; /* FIXME */
/* Unlock the service database */ @@ -5282,7 +5273,8 @@ memcpy(&lpStatusPtr->ServiceStatusProcess, &CurrentService->Status, sizeof(SERVICE_STATUS)); - lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */ + lpStatusPtr->ServiceStatusProcess.dwProcessId = + (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */ lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
lpStatusPtr++;
Modified: trunk/reactos/base/system/services/services.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/servic... ============================================================================== --- trunk/reactos/base/system/services/services.h [iso-8859-1] (original) +++ trunk/reactos/base/system/services/services.h [iso-8859-1] Sun Jul 17 15:45:03 2011 @@ -27,8 +27,14 @@
typedef struct _SERVICE_IMAGE { - DWORD dwServiceRefCount; // Number of running services of this image - DWORD Dummy; + LIST_ENTRY ImageListEntry; + DWORD dwImageRunCount; + + HANDLE hControlPipe; + HANDLE hProcess; + DWORD dwProcessId; + + WCHAR szImagePath[1]; } SERVICE_IMAGE, *PSERVICE_IMAGE;
@@ -54,10 +60,6 @@
BOOLEAN ServiceVisited;
- HANDLE ControlPipeHandle; - ULONG ProcessId; - ULONG ThreadId; - WCHAR szServiceName[1]; } SERVICE, *PSERVICE;
@@ -66,6 +68,7 @@
extern LIST_ENTRY ServiceListHead; extern LIST_ENTRY GroupListHead; +extern LIST_ENTRY ImageListHead; extern BOOL ScmShutdown;