This commit is contained in:
hakril 2025-05-29 21:32:06 -04:00 committed by GitHub
commit 504df8b4de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 173 additions and 61 deletions

View File

@ -183,6 +183,7 @@ ngx_module_t ngx_core_module = {
static ngx_uint_t ngx_show_help;
static ngx_uint_t ngx_show_version;
static ngx_uint_t ngx_show_configure;
static ngx_uint_t ngx_service = 0;
static u_char *ngx_prefix;
static u_char *ngx_error_log;
static u_char *ngx_conf_file;
@ -388,6 +389,56 @@ main(int argc, char *const *argv)
}
#ifdef NGX_WIN32
static ngx_int_t
ngx_install_windows_service()
{
wchar_t *install_commandline = NULL;
wchar_t *i_opt_ptr = NULL;
SC_HANDLE ScManagerHandle = NULL;
SC_HANDLE NginxServiceHandle = NULL;
// Replace install commandline by service run commandline by
// replacing the -i (install) option to a -w (windows service mode)
install_commandline = _wcsdup(GetCommandLineW());
i_opt_ptr = wcsstr(install_commandline, L" -i");
i_opt_ptr[2] = 'w';
printf("Installing NGINX service with commandline: %ls\n", install_commandline);
ScManagerHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (ScManagerHandle == NULL) {
ngx_log_stderr(0, "OpenSCManagerW failed: errno == %d", ngx_errno);
}
//"nginx" as service name is hardcoded is ngx_service : use a define ?
NginxServiceHandle = CreateServiceW(ScManagerHandle,
L"nginx",
L"Nginx server service",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, // Auto-start ? let user change it manually in windows interface ?
SERVICE_ERROR_NORMAL,
install_commandline,
NULL,
NULL,
NULL,
NULL, //L"NT AUTHORITY\\NetworkService", ?
NULL);
if (NginxServiceHandle == NULL) {
ngx_log_stderr(0, "CreateServiceW failed: errno == %d", ngx_errno);
CloseServiceHandle(ScManagerHandle);
} else {
printf("Service created !\n");
}
CloseServiceHandle(NginxServiceHandle);
CloseServiceHandle(ScManagerHandle);
return 0;
}
#endif
static void
ngx_show_version_info(void)
{
@ -929,6 +980,18 @@ ngx_get_options(int argc, char *const *argv)
ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
return NGX_ERROR;
#ifdef NGX_WIN32
case 'i':
ngx_install_windows_service();
exit(0); // Do something else ?
case 'w':
// Run as windows service
ngx_service = 1;
goto next;
#endif
default:
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
return NGX_ERROR;
@ -1086,6 +1149,12 @@ ngx_process_options(ngx_cycle_t *cycle)
cycle->log->log_level = NGX_LOG_INFO;
}
#if NGX_WIN32
if (ngx_service) {
cycle->service = 1;
}
#endif
return NGX_OK;
}

View File

@ -82,6 +82,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
cycle->log = log;
cycle->old_cycle = old_cycle;
cycle->service = old_cycle->service;
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
if (cycle->conf_prefix.data == NULL) {

View File

@ -83,6 +83,7 @@ struct ngx_cycle_s {
ngx_str_t error_log;
ngx_str_t lock_file;
ngx_str_t hostname;
ngx_uint_t service;
};

View File

@ -26,7 +26,11 @@ static ngx_thread_value_t __stdcall ngx_worker_thread(void *data);
static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data);
static void ngx_cache_manager_process_handler(void);
static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data);
static ngx_thread_value_t __stdcall ngx_service_thread(void *data);
/* TODO: ngx_service.h */
ngx_int_t ngx_service(ngx_log_t *log);
ngx_uint_t ngx_process;
ngx_uint_t ngx_worker;
@ -46,7 +50,7 @@ ngx_uint_t ngx_exiting;
HANDLE ngx_master_process_event;
char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME];
static HANDLE ngx_stop_event;
HANDLE ngx_stop_event;
static char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME];
static HANDLE ngx_quit_event;
static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME];
@ -68,6 +72,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_int_t n;
ngx_msec_t timer;
ngx_uint_t live;
ngx_tid_t servicetid;
HANDLE events[MAXIMUM_WAIT_OBJECTS];
ngx_sprintf((u_char *) ngx_master_process_event_name,
@ -116,6 +121,14 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_close_listening_sockets(cycle);
if (cycle->service){
// Create only if this thread does not already exists ?
if (ngx_create_thread(&servicetid, ngx_service_thread, NULL, cycle->log) != 0) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "Creating ngx_service_thread failed");
exit(2);
}
}
if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) {
exit(2);
}
@ -754,7 +767,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn)
ngx_worker_process_exit(cycle);
failed:
exit(2);
}
@ -981,6 +993,11 @@ ngx_cache_loader_thread(void *data)
return 0;
}
static ngx_thread_value_t __stdcall
ngx_service_thread(void *data)
{
return ngx_service((ngx_log_t*)data);
}
void
ngx_single_process_cycle(ngx_cycle_t *cycle)

View File

@ -4,131 +4,154 @@
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#define NGX_SERVICE_CONTROL_SHUTDOWN 128
#define NGX_SERVICE_CONTROL_REOPEN 129
HANDLE ngx_stop_event; // Defined in src\os\win32\ngx_process_cycle.c
/*
void LpserviceMainFunctiona(
[in] DWORD dwNumServicesArgs,
[in] LPSTR *lpServiceArgVectors
)
*/
void WINAPI service_main(DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors);
SERVICE_TABLE_ENTRY st[] = {
{ "nginx", service_main },
/*
DWORD LphandlerFunctionEx(
[in] DWORD dwControl,
[in] DWORD dwEventType,
[in] LPVOID lpEventData,
[in] LPVOID lpContext
)
*/
DWORD WINAPI service_handler(DWORD control, DWORD type, void *data, void *ctx);
SERVICE_STATUS_HANDLE service = 0; // Put this field in ngx_cycle ?
SERVICE_TABLE_ENTRY service_table[] = {
{ "nginx", service_main},
{ NULL, NULL }
};
ngx_int_t
ngx_service(ngx_log_t *log)
ngx_service()
{
/* primary thread */
/* StartServiceCtrlDispatcher() should be called within 30 seconds */
if (StartServiceCtrlDispatcher(st) == 0) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
if (StartServiceCtrlDispatcher(service_table) == 0) {
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
"StartServiceCtrlDispatcher() failed");
return NGX_ERROR;
}
return NGX_OK;
}
void
service_main(u_int argc, char **argv)
void WINAPI
service_main(DWORD dwNumServicesArgs, LPSTR *lpServiceArgVectors)
{
SERVICE_STATUS status;
SERVICE_STATUS_HANDLE service;
/* thread spawned by SCM */
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx);
service = RegisterServiceCtrlHandlerEx("nginx", service_handler, NULL);
if (service == INVALID_HANDLE_VALUE) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
"RegisterServiceCtrlHandlerEx() failed");
return;
}
/* Use a more generic report_service_status ? */
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PARAMCHANGE;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwWin32ExitCode = NO_ERROR;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 1;
status.dwWaitHint = 2000;
/* SetServiceStatus() should be called within 80 seconds */
if (SetServiceStatus(service, &status) == 0) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
"SetServiceStatus() failed");
return;
}
/* init */
// Do we have any init to wait for ?
// Init seems preety well advanced when the service thread is created
status.dwCurrentState = SERVICE_RUNNING;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
if (SetServiceStatus(service, &status) == 0) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
"SetServiceStatus() failed");
return;
}
/* call master or worker loop */
}
/*
* master should use event notification and look status
* single should use iocp to get notifications from service handler
*/
int report_service_stop_status(DWORD dwCurrentState)
{
SERVICE_STATUS status;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = dwCurrentState;
status.dwControlsAccepted = 0;
status.dwWin32ExitCode = NO_ERROR;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
/* SetServiceStatus() should be called within 80 seconds */
if (SetServiceStatus(service, &status) == 0) {
return 1;
}
return 0;
}
u_int
service_handler(u_int control, u_int type, void *data, void *ctx)
DWORD WINAPI
service_handler(DWORD control, DWORD type, void *data, void *ctx)
{
/* primary thread */
switch (control) {
case SERVICE_CONTROL_INTERROGATE:
status = NGX_IOCP_INTERROGATE;
break;
switch (control) {
// case SERVICE_CONTROL_INTERROGATE:
// status = NGX_IOCP_INTERROGATE;
// break;
//
case SERVICE_CONTROL_STOP:
status = NGX_IOCP_STOP;
break;
case SERVICE_CONTROL_PARAMCHANGE:
status = NGX_IOCP_RECONFIGURE;
break;
case NGX_SERVICE_CONTROL_SHUTDOWN:
status = NGX_IOCP_REOPEN;
break;
case NGX_SERVICE_CONTROL_REOPEN:
status = NGX_IOCP_REOPEN;
report_service_stop_status(SERVICE_STOP_PENDING);
if (SetEvent(ngx_stop_event) == 0) {
ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
"SetEvent(ngx_stop_event) failed");
}
report_service_stop_status(SERVICE_STOPPED);
break;
//
// case SERVICE_CONTROL_PARAMCHANGE:
// status = NGX_IOCP_RECONFIGURE;
// break;
//
// case NGX_SERVICE_CONTROL_SHUTDOWN:
// status = NGX_IOCP_REOPEN;
// break;
//
// case NGX_SERVICE_CONTROL_REOPEN:
// status = NGX_IOCP_REOPEN;
// break;
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
if (ngx_single) {
if (PostQueuedCompletionStatus(iocp, ... status, ...) == 0) {
err = ngx_errno;
ngx_log_error(NGX_LOG_ALERT, log, err,
"PostQueuedCompletionStatus() failed");
return err;
}
} else {
Event
}
return NO_ERROR;
}