📄 service.c
字号:
ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 0); }long __stdcall service_stderr_thread(LPVOID hPipe){ HANDLE hPipeRead = (HANDLE) hPipe; HANDLE hEventSource; char errbuf[256]; char *errmsg = errbuf; const char *errarg[9]; DWORD errlen = 0; DWORD errres; HKEY hk; errarg[0] = "The Apache service named"; errarg[1] = display_name; errarg[2] = "reported the following error:\r\n>>>"; errarg[3] = errmsg; errarg[4] = "<<<\r\n before the error.log file could be opened.\r\n"; errarg[5] = "More information may be available in the error.log file."; errarg[6] = NULL; errarg[7] = NULL; errarg[8] = NULL; /* What are we going to do in here, bail on the user? not. */ if (!RegCreateKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services" "\\EventLog\\Application\\Apache Service", &hk)) { /* The stock message file */ char *netmsgkey = "%SystemRoot%\\System32\\netmsg.dll"; DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) netmsgkey, strlen(netmsgkey) + 1); RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(dwData)); RegCloseKey(hk); } hEventSource = RegisterEventSource(NULL, "Apache Service"); while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) { if ((errmsg > errbuf) || !isspace(*errmsg)) { ++errlen; ++errmsg; if ((*(errmsg - 1) == '\n') || (errlen == sizeof(errbuf) - 1)) { while (errlen && isspace(errbuf[errlen - 1])) --errlen; errbuf[errlen] = '\0'; /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' * The event code in netmsg.dll is 3299 */ ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, errarg, NULL); errmsg = errbuf; errlen = 0; } } } CloseHandle(hPipeRead); return 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;static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv){ HANDLE waitfor[2]; HANDLE hCurrentProcess; HANDLE hPipeRead = NULL; HANDLE hPipeWrite = NULL; HANDLE hPipeReadDup; HANDLE thread; DWORD threadid; SECURITY_ATTRIBUTES sa = {0}; /* args and service names live in the same pool */ mpm_service_set_name(mpm_new_argv->cont, argv[0]); globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING; globdat.ssStatus.dwServiceSpecificExitCode = 0; globdat.ssStatus.dwCheckPoint = 1; 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"); PulseEvent(globdat.signal_monitor); return; } ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, // service state NO_ERROR, // exit code 3000); // wait hint, 3 seconds more /* Create a pipe to send stderr messages to the system error log */ hCurrentProcess = GetCurrentProcess(); if (CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) { if (DuplicateHandle(hCurrentProcess, hPipeRead, hCurrentProcess, &hPipeReadDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { CloseHandle(hPipeRead); hPipeRead = hPipeReadDup; thread = CreateThread(NULL, 0, service_stderr_thread, (LPVOID) hPipeRead, 0, &threadid); if (thread) { int fh; FILE *fl; CloseHandle(thread); fflush(stderr); SetStdHandle(STD_ERROR_HANDLE, hPipeWrite); fh = _open_osfhandle((long) STD_ERROR_HANDLE, _O_WRONLY | _O_BINARY); dup2(fh, STDERR_FILENO); fl = _fdopen(STDERR_FILENO, "wcb"); memcpy(stderr, fl, sizeof(FILE)); } else { CloseHandle(hPipeRead); CloseHandle(hPipeWrite); hPipeWrite = NULL; } } else { CloseHandle(hPipeRead); CloseHandle(hPipeWrite); hPipeWrite = NULL; } } /* 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 = apr_palloc(mpm_new_argv->cont, 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.signal_monitor); waitfor[0] = globdat.signal_monitor; waitfor[1] = globdat.mpm_thread; WaitForMultipleObjects(2, waitfor, FALSE, INFINITE); /* The process is ready to terminate, or already has */ CloseHandle(hPipeWrite);}DWORD WINAPI service_nt_dispatch_thread(LPVOID nada){ apr_status_t rv = APR_SUCCESS; SERVICE_TABLE_ENTRY dispatchTable[] = { { "", service_nt_main_fn }, { NULL, NULL } }; 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"); } globdat.service_thread_id = 0; return (rv);}apr_status_t mpm_service_set_name(apr_pool_t *p, const char *name){ char *key_name; service_name = apr_palloc(p, strlen(name) + 1); apr_collapse_spaces((char*) service_name, name); key_name = apr_psprintf(p, SERVICECONFIG, service_name); if (ap_registry_get_value(p, key_name, "DisplayName", (char**)&display_name) == APR_SUCCESS) return APR_SUCCESS; /* Take the given literal name if there is no service entry */ display_name = apr_pstrdup(p, name); return APR_ENOFILE;}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; apr_snprintf(conf_key, sizeof(conf_key), SERVICEPARAMS, service_name); rv = ap_registry_get_array(p, conf_key, "ConfigArgs", &svc_args); if (rv != APR_SUCCESS) { if (rv == ERROR_FILE_NOT_FOUND) { ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, NULL, "No ConfigArgs registered for %s, perhaps " "this service is not installed?", service_name); return APR_SUCCESS; } else return (rv); } if (!svc_args || svc_args->nelts == 0) { return (APR_SUCCESS); } /* Now we have the 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 = apr_palloc(p, 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;}void service_stopped(void){ /* Still have a thread & window to clean up, so signal now */ if (globdat.service_thread_id) { if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { ReportStatusToSCMgr(SERVICE_STOPPED, // service state NO_ERROR, // exit code 0); // wait hint /* Cause the service_nt_main_fn to complete */ SetEvent(globdat.signal_monitor); } else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ { RegisterServiceProcess(0, 0); PostThreadMessage(globdat.service_thread_id, WM_CLOSE, 0, 0); } WaitForSingleObject(globdat.service_thread, 5000); CloseHandle(globdat.service_thread); }}apr_status_t mpm_service_to_start(void){ HANDLE waitfor[2]; globdat.mpm_thread = GetCurrentThread(); if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { globdat.signal_monitor = CreateEvent(NULL, FALSE, FALSE, NULL); if (globdat.signal_monitor) globdat.service_thread = CreateThread(NULL, 0, service_nt_dispatch_thread, NULL, 0, &globdat.service_thread_id); } else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ { if (!RegisterServiceProcess(0, 1)) return GetLastError(); globdat.signal_monitor = CreateEvent(NULL, FALSE, FALSE, NULL); if (globdat.signal_monitor) globdat.service_thread = CreateThread(NULL, 0, monitor_service_9x_thread, (LPVOID) service_name, 0, &globdat.service_thread_id); } if (globdat.signal_monitor && globdat.service_thread) { waitfor[0] = globdat.signal_monitor; waitfor[1] = globdat.service_thread; /* SetEvent(globdat.signal_monitor) to clean up the SCM thread */ if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) { CloseHandle(globdat.service_thread); return APR_ENOTHREAD; } } if (globdat.service_thread_id) atexit(service_stopped); else if (globdat.service_thread) CloseHandle(globdat.service_thread); return APR_SUCCESS;}apr_status_t mpm_service_started(void){ if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { ReportStatusToSCMgr(SERVICE_RUNNING, // service state NO_ERROR, // exit code 0); // wait hint } return APR_SUCCESS;}void mpm_service_stopping(void){ if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) ReportStatusToSCMgr(SERVICE_STOP_PENDING, // service state NO_ERROR, // exit code 3000); // wait hint}apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, const char * const * argv){ char key_name[MAX_PATH]; char exe_path[MAX_PATH]; char *launch_cmd; apr_status_t(rv); printf("Installing the %s service\n", display_name); if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0) { apr_status_t rv = apr_get_os_error(); ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, "GetModuleFileName failed"); return rv; } if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { SC_HANDLE schService; SC_HANDLE schSCManager; // TODO: Determine the minimum permissions required for security schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ SC_MANAGER_ALL_ACCESS); if (!schSCManager) { rv = apr_get_os_error(); ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, "Failed to open the WinNT service manager"); return (rv); } launch_cmd = apr_psprintf(ptemp, "\"%s\" -k runservice", exe_path); /* RPCSS is the Remote Procedure Call (RPC) Locator required for DCOM * communication pipes. I am far from convinced we should add this to * the default service dependencies, but be warned that future apache * modules or ISAPI dll's may depend on it. */ schService = CreateService(schSCManager, // SCManager database service_name, // name of service display_name, // name to display SERVICE_ALL_ACCESS, // access required SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type launch_cmd, // service's binary NULL, // no load svc group NULL, // no tag identifier "Tcpip\0Afd\0", // dependencies
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -