📄 service.c
字号:
* The system will also signal the parent process,
* which will terminate Apache, so we need to wait.
*/
Sleep(30000);
return TRUE;
}
/* We should never get here, but this is (mostly) harmless */
return FALSE;
}
static void stop_child_console_handler(void)
{
SetConsoleCtrlHandler(child_control_handler, FALSE);
}
void mpm_start_child_console_handler(void)
{
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
FreeConsole();
}
else
{
SetConsoleCtrlHandler(child_control_handler, TRUE);
atexit(stop_child_console_handler);
}
}
/**********************************
WinNT service control management
**********************************/
static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint)
{
static int checkPoint = 1;
int rv = APR_SUCCESS;
if (globdat.hServiceStatus)
{
if (currentState == SERVICE_RUNNING) {
globdat.ssStatus.dwWaitHint = 0;
globdat.ssStatus.dwCheckPoint = 0;
globdat.ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
}
else if (currentState == SERVICE_STOPPED) {
globdat.ssStatus.dwWaitHint = 0;
globdat.ssStatus.dwCheckPoint = 0;
if (!exitCode && globdat.ssStatus.dwCurrentState
!= SERVICE_STOP_PENDING) {
/* An unexpected exit? Better to error! */
exitCode = 1;
}
if (exitCode) {
globdat.ssStatus.dwWin32ExitCode =ERROR_SERVICE_SPECIFIC_ERROR;
globdat.ssStatus.dwServiceSpecificExitCode = exitCode;
}
}
else {
globdat.ssStatus.dwCheckPoint = ++checkPoint;
globdat.ssStatus.dwControlsAccepted = 0;
if(waitHint)
globdat.ssStatus.dwWaitHint = waitHint;
}
globdat.ssStatus.dwCurrentState = currentState;
rv = SetServiceStatus(globdat.hServiceStatus, &globdat.ssStatus);
}
return(rv);
}
/* Set the service description regardless of platform.
* We revert to set_service_description on NT/9x, the
* very long way so any Apache management program can grab the
* description. This would be bad on Win2000, since it wouldn't
* notify the service control manager of the name change.
*/
/* borrowed from mpm_winnt.c */
extern apr_pool_t *pconf;
/* Windows 2000 alone supports ChangeServiceConfig2 in order to
* register our server_version string... so we need some fixups
* to avoid binding to that function if we are on WinNT/9x.
*/
static void set_service_description(void)
{
const char *full_description;
SC_HANDLE schSCManager;
BOOL ret = 0;
/* Nothing to do if we are a console
*/
if (!mpm_service_name)
return;
/* Time to fix up the description, upon each successful restart
*/
full_description = ap_get_server_version();
if ((osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
&& (osver.dwMajorVersion > 4)
&& (ChangeServiceConfig2)
&& (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)))
{
SC_HANDLE schService = OpenService(schSCManager, mpm_service_name,
SERVICE_CHANGE_CONFIG);
if (schService) {
/* Cast is necessary, ChangeServiceConfig2 handles multiple
* object types, some volatile, some not.
*/
/* ###: utf-ize */
if (ChangeServiceConfig2(schService,
1 /* SERVICE_CONFIG_DESCRIPTION */,
(LPVOID) &full_description)) {
full_description = NULL;
}
CloseServiceHandle(schService);
}
CloseServiceHandle(schSCManager);
}
if (full_description)
{
char szPath[MAX_PATH];
ap_regkey_t *svckey;
apr_status_t rv;
/* Find the Service key that Monitor Applications iterate */
apr_snprintf(szPath, sizeof(szPath),
"SYSTEM\\CurrentControlSet\\Services\\%s",
mpm_service_name);
rv = ap_regkey_open(&svckey, AP_REGKEY_LOCAL_MACHINE, szPath,
APR_READ | APR_WRITE, pconf);
if (rv != APR_SUCCESS) {
return;
}
/* Attempt to set the Description value for our service */
ap_regkey_value_set(svckey, "Description", full_description, 0, pconf);
ap_regkey_close(svckey);
}
}
/* handle the SCM's ControlService() callbacks to our service */
static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode)
{
if (dwCtrlCode == SERVICE_CONTROL_STOP)
{
ap_signal_parent(SIGNAL_PARENT_SHUTDOWN);
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 30000);
return;
}
if (dwCtrlCode == SERVICE_APACHE_RESTART)
{
ap_signal_parent(SIGNAL_PARENT_RESTART);
ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000);
return;
}
ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 0);
}
/* service_nt_main_fn is outside of the call stack and outside of the
* primary server thread... so now we _really_ need a placeholder!
* The winnt_rewrite_args has created and shared mpm_new_argv with us.
*/
extern apr_array_header_t *mpm_new_argv;
/* ###: utf-ize */
static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
{
const char *ignored;
/* args and service names live in the same pool */
mpm_service_set_name(mpm_new_argv->pool, &ignored, argv[0]);
memset(&globdat.ssStatus, 0, sizeof(globdat.ssStatus));
globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
globdat.ssStatus.dwCheckPoint = 1;
/* ###: utf-ize */
if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl)))
{
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(),
NULL, "Failure registering service handler");
return;
}
/* Report status, no errors, and buy 3 more seconds */
ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000);
/* We need to append all the command arguments passed via StartService()
* to our running service... which just got here via the SCM...
* but we hvae no interest in argv[0] for the mpm_new_argv list.
*/
if (argc > 1)
{
char **cmb_data;
mpm_new_argv->nalloc = mpm_new_argv->nelts + argc - 1;
cmb_data = malloc(mpm_new_argv->nalloc * sizeof(const char *));
/* mpm_new_argv remains first (of lower significance) */
memcpy (cmb_data, mpm_new_argv->elts,
mpm_new_argv->elt_size * mpm_new_argv->nelts);
/* Service args follow from StartService() invocation */
memcpy (cmb_data + mpm_new_argv->nelts, argv + 1,
mpm_new_argv->elt_size * (argc - 1));
/* The replacement arg list is complete */
mpm_new_argv->elts = (char *)cmb_data;
mpm_new_argv->nelts = mpm_new_argv->nalloc;
}
/* Let the main thread continue now... but hang on to the
* signal_monitor event so we can take further action
*/
SetEvent(globdat.service_init);
WaitForSingleObject(globdat.service_term, INFINITE);
}
DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
{
apr_status_t rv = APR_SUCCESS;
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{ "", service_nt_main_fn },
{ NULL, NULL }
};
/* ###: utf-ize */
if (!StartServiceCtrlDispatcher(dispatchTable))
{
/* This is a genuine failure of the SCM. */
rv = apr_get_os_error();
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
"Error starting service control dispatcher");
}
return (rv);
}
apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name,
const char *set_name)
{
char key_name[MAX_PATH];
ap_regkey_t *key;
apr_status_t rv;
/* ### Needs improvement, on Win2K the user can _easily_
* change the display name to a string that doesn't reflect
* the internal service name + whitespace!
*/
mpm_service_name = apr_palloc(p, strlen(set_name) + 1);
apr_collapse_spaces((char*) mpm_service_name, set_name);
apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name);
rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, APR_READ, pconf);
if (rv == APR_SUCCESS) {
rv = ap_regkey_value_get(&mpm_display_name, key, "DisplayName", pconf);
ap_regkey_close(key);
}
if (rv != APR_SUCCESS) {
/* Take the given literal name if there is no service entry */
mpm_display_name = apr_pstrdup(p, set_name);
}
*display_name = mpm_display_name;
return rv;
}
apr_status_t mpm_merge_service_args(apr_pool_t *p,
apr_array_header_t *args,
int fixed_args)
{
apr_array_header_t *svc_args = NULL;
char conf_key[MAX_PATH];
char **cmb_data;
apr_status_t rv;
ap_regkey_t *key;
apr_snprintf(conf_key, sizeof(conf_key), SERVICEPARAMS, mpm_service_name);
rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, conf_key, APR_READ, p);
if (rv == APR_SUCCESS) {
rv = ap_regkey_value_array_get(&svc_args, key, "ConfigArgs", p);
ap_regkey_close(key);
}
if (rv != APR_SUCCESS) {
if (rv == ERROR_FILE_NOT_FOUND) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL,
"No ConfigArgs registered for %s, perhaps "
"this service is not installed?",
mpm_service_name);
return APR_SUCCESS;
}
else
return (rv);
}
if (!svc_args || svc_args->nelts == 0) {
return (APR_SUCCESS);
}
/* Now we have the mpm_service_name arg, and the mpm_runservice_nt()
* call appended the arguments passed by StartService(), so it's
* time to _prepend_ the default arguments for the server from
* the service's default arguments (all others override them)...
*/
args->nalloc = args->nelts + svc_args->nelts;
cmb_data = malloc(args->nalloc * sizeof(const char *));
/* First three args (argv[0], -f, path) remain first */
memcpy(cmb_data, args->elts, args->elt_size * fixed_args);
/* Service args follow from service registry array */
memcpy(cmb_data + fixed_args, svc_args->elts,
svc_args->elt_size * svc_args->nelts);
/* Remaining new args follow */
memcpy(cmb_data + fixed_args + svc_args->nelts,
(const char **)args->elts + fixed_args,
args->elt_size * (args->nelts - fixed_args));
args->elts = (char *)cmb_data;
args->nelts = args->nalloc;
return APR_SUCCESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -