8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/iscguard/cntl_guard.cpp

290 lines
7.2 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Guardian CNTL function.
* MODULE: cntl_guard.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Windows NT service control panel interface
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include "../jrd/common.h"
#include "../iscguard/cntlg_proto.h"
#include "../remote/remote.h"
2003-07-15 04:43:36 +02:00
#include "../utilities/install/install_nt.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/thd.h"
#include "../jrd/isc_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sch_proto.h"
#include "../common/classes/fb_string.h"
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
#include <windows.h>
#endif
struct thread {
2003-09-17 12:36:11 +02:00
thread* thread_next;
2001-05-23 15:26:42 +02:00
HANDLE thread_handle;
};
2001-05-23 15:26:42 +02:00
static void WINAPI control_thread(DWORD);
static void parse_switch(const TEXT*, int*);
2001-05-23 15:26:42 +02:00
static USHORT report_status(DWORD, DWORD, DWORD, DWORD);
static DWORD current_state;
static ThreadEntryPoint* main_handler;
2001-05-23 15:26:42 +02:00
static SERVICE_STATUS_HANDLE service_handle;
static Firebird::string* service_name = NULL;
static Firebird::string* remote_name = NULL;
2001-05-23 15:26:42 +02:00
static HANDLE stop_event_handle;
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
static MUTX_T thread_mutex[1];
static thread* threads;
#endif
2001-05-23 15:26:42 +02:00
void CNTL_init(ThreadEntryPoint* handler, const TEXT* name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C N T L _ i n i t
*
**************************************
*
* Functional description
*
**************************************/
main_handler = handler;
MemoryPool& pool = *getDefaultMemoryPool();
service_name = FB_NEW(pool) Firebird::string(pool);
service_name->printf(ISCGUARD_SERVICE, name);
remote_name = FB_NEW(pool) Firebird::string(pool);
remote_name->printf(REMOTE_SERVICE, name);
2001-05-23 15:26:42 +02:00
}
void WINAPI CNTL_main_thread( DWORD argc, char* argv[])
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C N T L _ m a i n _ t h r e a d
*
**************************************
*
* Functional description
*
**************************************/
service_handle =
RegisterServiceCtrlHandler(service_name->c_str(), control_thread);
2001-05-23 15:26:42 +02:00
if (!service_handle)
return;
// THD_mutex_init (thread_mutex);
2001-05-23 15:26:42 +02:00
/* start everything, and wait here for ever, or at
* least until we get the stop event indicating that
* the service is stoping. */
2004-12-09 03:50:47 +01:00
bool failure = true;
DWORD temp = 0;
2001-05-23 15:26:42 +02:00
if (report_status(SERVICE_START_PENDING, NO_ERROR, 1, 3000) &&
(stop_event_handle = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL &&
report_status(SERVICE_START_PENDING, NO_ERROR, 2, 3000) &&
!gds__thread_start(main_handler, NULL, 0, 0, 0)
&& report_status(SERVICE_RUNNING, NO_ERROR, 0, 0))
{
2004-12-09 03:50:47 +01:00
failure = false;
2001-05-23 15:26:42 +02:00
temp = WaitForSingleObject(stop_event_handle, INFINITE);
}
DWORD last_error = 0;
2004-12-09 03:50:47 +01:00
if (failure || temp == WAIT_FAILED)
2001-05-23 15:26:42 +02:00
last_error = GetLastError();
if (stop_event_handle)
CloseHandle(stop_event_handle);
/* ONce we are stopped, we will tell the server to
* do the same. We could not do this in the control_thread
* since the Services Control Manager is single threaded,
* and thus can only process one request at the time. */
SERVICE_STATUS status_info;
SC_HANDLE hScManager = 0, hService = 0;
hScManager =
OpenSCManager(NULL, NULL, GENERIC_READ);
hService = OpenService(hScManager, remote_name->c_str(),
GENERIC_READ | GENERIC_EXECUTE);
ControlService(hService, SERVICE_CONTROL_STOP, &status_info);
CloseServiceHandle(hScManager);
CloseServiceHandle(hService);
2001-05-23 15:26:42 +02:00
report_status(SERVICE_STOPPED, last_error, 0, 0);
// THD_mutex_destroy (thread_mutex);
2001-05-23 15:26:42 +02:00
}
void CNTL_shutdown_service(const TEXT* message)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C N T L _ s h u t d o w n _ s e r v i c e
*
**************************************
*
* Functional description
*
**************************************/
const char* strings[2];
2005-08-31 18:08:14 +02:00
char buffer[BUFFER_SMALL];
2001-05-23 15:26:42 +02:00
sprintf(buffer, "%s error: %lu", service_name->c_str(), GetLastError());
2001-05-23 15:26:42 +02:00
HANDLE event_source = RegisterEventSource(NULL, service_name->c_str());
2001-05-23 15:26:42 +02:00
if (event_source) {
strings[0] = buffer;
strings[1] = message;
ReportEvent(event_source,
EVENTLOG_ERROR_TYPE,
0,
0,
NULL, 2, 0, strings, NULL);
2001-05-23 15:26:42 +02:00
DeregisterEventSource(event_source);
}
if (stop_event_handle)
SetEvent(stop_event_handle);
}
void CNTL_stop_service(const TEXT* service) // unused param
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C N T L _ s t o p _ s e r v i c e
*
**************************************
*
* Functional description
* This function is called to stop the service.
*
*
**************************************/
SC_HANDLE servicemgr_handle = OpenSCManager(NULL, NULL, GENERIC_READ);
2001-05-23 15:26:42 +02:00
if (servicemgr_handle == NULL) {
// return error
int error = GetLastError();
gds__log("SC manager error %d", error);
return;
}
2004-05-12 21:23:17 +02:00
SC_HANDLE service_handleL =
OpenService(servicemgr_handle, service_name->c_str(),
2003-09-10 15:20:39 +02:00
GENERIC_READ | GENERIC_EXECUTE);
2001-05-23 15:26:42 +02:00
2004-05-12 21:23:17 +02:00
if (service_handleL == NULL) {
2001-05-23 15:26:42 +02:00
// return error
int error = GetLastError();
gds__log("open services error %d", error);
return;
}
else {
SERVICE_STATUS status_info;
2001-05-23 15:26:42 +02:00
if (!ControlService
2004-05-12 21:23:17 +02:00
(service_handleL, SERVICE_CONTROL_STOP, &status_info))
{
2001-05-23 15:26:42 +02:00
// return error
const int error = GetLastError();
2001-05-23 15:26:42 +02:00
gds__log("Control services error %d", error);
return;
}
}
}
static void WINAPI control_thread( DWORD action)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c o n t r o l _ t h r e a d
*
**************************************
*
* Functional description
* Process a service control request.
*
**************************************/
const DWORD state = SERVICE_RUNNING;
2001-05-23 15:26:42 +02:00
switch (action) {
case SERVICE_CONTROL_STOP:
report_status(SERVICE_STOP_PENDING, NO_ERROR, 1, 3000);
SetEvent(stop_event_handle);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
report_status(state, NO_ERROR, 0, 0);
}
static USHORT report_status(
DWORD state,
DWORD exit_code, DWORD checkpoint, DWORD hint)
{
/**************************************
*
* r e p o r t _ s t a t u s
*
**************************************
*
* Functional description
* Report our status to the control manager.
*
**************************************/
SERVICE_STATUS status;
status.dwServiceType =
(SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS);
status.dwServiceSpecificExitCode = 0;
if (state == SERVICE_START_PENDING)
status.dwControlsAccepted = 0;
else
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwCurrentState = current_state = state;
status.dwWin32ExitCode = exit_code;
status.dwCheckPoint = checkpoint;
status.dwWaitHint = hint;
const USHORT ret = SetServiceStatus(service_handle, &status);
if (!ret)
2001-05-23 15:26:42 +02:00
CNTL_shutdown_service("SetServiceStatus");
return ret;
}