#define AP_LISTEN_H
#include "apr_network_io.h"
+#include "http_config.h"
typedef struct ap_listen_rec ap_listen_rec;
struct ap_listen_rec {
extern ap_array_header_t *ap_server_post_read_config;
extern ap_array_header_t *ap_server_config_defines;
+#ifdef WIN32
+API_EXPORT(int) apache_main(int argc, char *argv[]);
+#endif
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/*
+ * Declarations for users of the functions defined in registry.c
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif
+#ifndef NOGDI
+#define NOGDI
+#endif
+#ifndef NONLS
+#define NONLS
+#endif
+#ifndef NOMCX
+#define NOMCX
+#endif
+#ifndef NOIME
+#define NOIME
+#endif
+#include <windows.h>
+#include <winsock2.h>
+#include <mswsock.h>
#include "ap_config.h"
#include "ap_listen.h"
#include "mpm_default.h"
-//#include "service.h"
#include "iol_socket.h"
#include "winnt.h"
-
/*
* Definitions of WINNT MPM specific config globals
*/
static event *exit_event;
HANDLE maintenance_event;
ap_lock_t *start_mutex;
-int my_pid;
-int parent_pid;
-typedef void (CALLBACK *ap_completion_t)();
+DWORD my_pid;
+DWORD parent_pid;
API_VAR_EXPORT ap_completion_t ap_mpm_init_complete = NULL;
static ap_status_t socket_cleanup(void *sock)
}
CloseHandle(e);
}
+
static int volatile is_graceful = 0;
+
API_EXPORT(int) ap_graceful_stop_signalled(void)
{
return is_graceful;
}
-void ap_start_shutdown(void)
+
+API_EXPORT(void) ap_start_shutdown(void)
{
signal_parent(0);
}
+
/*
* Initialise the signal names, in the global variables signal_name_prefix,
* signal_restart_name and signal_shutdown_name.
* Routines to deal with managing the list of listening sockets.
*/
static ap_listen_rec *head_listener;
+
static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
{
ap_listen_rec *lr;
}
return NULL;
}
+
static int setup_listeners(server_rec *s)
{
ap_listen_rec *lr;
int rv;
char buf[1024];
char *pCommand;
+ char *pEnvVar;
+ char *pEnvBlock;
int i;
+ int iEnvBlockLen;
STARTUPINFO si; /* Filled in prior to call to CreateProcess */
PROCESS_INFORMATION pi; /* filled in on call to CreateProces */
pCommand = ap_pstrcat(p, pCommand, " \"", server_conf->process->argv[i], "\"", NULL);
}
+ /* Build the environment, since Win9x disrespects the active env */
+ // SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%l",parent_pid));
+ pEnvVar = ap_psprintf(p, "AP_PARENT_PID=%i", parent_pid);
+ /*
+ * Win32's CreateProcess call requires that the environment
+ * be passed in an environment block, a null terminated block of
+ * null terminated strings.
+ */
+ i = 0;
+ iEnvBlockLen = 1;
+ while (_environ[i]) {
+ iEnvBlockLen += strlen(_environ[i]) + 1;
+ i++;
+ }
+
+ pEnvBlock = (char *)ap_pcalloc(p, iEnvBlockLen + strlen(pEnvVar) + 1);
+ strcpy(pEnvBlock, pEnvVar);
+ pEnvVar = strchr(pEnvBlock, '\0') + 1;
+
+ i = 0;
+ while (_environ[i]) {
+ strcpy(pEnvVar, _environ[i]);
+ pEnvVar = strchr(pEnvVar, '\0') + 1;
+ i++;
+ }
+ pEnvVar = '\0';
/* Create a pipe to send socket info to the child */
if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
return -1;
}
- SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%d",parent_pid));
-
/* Give the read end of the pipe (hPipeRead) to the child as stdin. The
* parent will write the socket data to the child on this pipe.
*/
if (!CreateProcess(NULL, pCommand, NULL, NULL,
TRUE, /* Inherit handles */
CREATE_SUSPENDED, /* Creation flags */
- NULL, /* Environment block */
+ pEnvBlock, /* Environment block */
NULL,
&si, &pi)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
pid = getenv("AP_PARENT_PID");
if (pid) {
/* This is the child */
- parent_pid = atoi(pid);
- my_pid = getpid();
+ parent_pid = (DWORD) atol(pid);
+ my_pid = GetCurrentProcessId();
}
else {
/* This is the parent */
- parent_pid = my_pid = getpid();
+ parent_pid = my_pid = GetCurrentProcessId();
}
ap_listen_pre_config();
if (pidfile != NULL && unlink(pidfile) == 0) {
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,APR_SUCCESS,
server_conf, "removed PID file %s (pid=%ld)",
- pidfile, (long)getpid());
+ pidfile, GetCurrentProcessId());
}
ap_destroy_lock(start_mutex);
#ifndef APACHE_MPM_WINNT_H
#define APACHE_MPM_WINNT_H
+#include "ap_listen.h"
+
extern int ap_threads_per_child;
extern int ap_max_requests_per_child;
extern int ap_extended_status;
extern void clean_child_exit(int);
+typedef void (CALLBACK *ap_completion_t)();
+API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
+
+API_EXPORT(void) ap_start_shutdown(void);
typedef struct CompContext {
OVERLAPPED Overlapped;
#define SERVICEKEYPRE "System\\CurrentControlSet\\Services\\"
#define SERVICEKEYPOST "\\Parameters"
+#define SERVICELAUNCH9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices\\"
/*
* The Windows API registry key functions don't set the last error
* value (the windows equivalent of errno). So we need to set it
* dir will contain an empty string), or -1 if there was
* an error getting the key.
*/
-#if 0
-int ap_registry_get_server_root(ap_pool_t *p, char *dir, int size)
-{
- int rv;
-
- rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL);
- if (rv < 0) {
- dir[0] = '\0';
- }
-
- return (rv < -1) ? -1 : 0;
-}
-#else
int ap_registry_get_server_root(ap_pool_t *p, char **buf)
{
int rv;
return (rv < -1) ? -1 : 0;
}
-#endif
+
char *ap_get_service_key(char *display_name)
{
size_t keylen = strlen(display_name);
return(key);
}
-#if 0
-int ap_registry_get_service_conf(ap_pool_t *p, char *dir, int size, char *display_name)
-{
- int rv;
- char *key = ap_get_service_key(display_name);
-
- rv = ap_registry_get_key_int(p, key, "ConfPath", dir, size, NULL);
- if (rv < 0) {
- dir[0] = '\0';
- }
- free(key);
- return (rv < -1) ? -1 : 0;
-}
-#else
int ap_registry_get_service_conf(ap_pool_t *p, char **buf, char *service_name)
{
int rv;
free(key);
return (rv < -1) ? -1 : 0;
}
-#endif
/**********************************************************************
* The rest of this file deals with storing keys or values in the registry
return rv < 0 ? -1 : 0;
}
-
#ifdef WIN32
-#include "os.h"
-#include <stdlib.h>
-#include <direct.h>
-
#define CORE_PRIVATE
+
+#include "main_win32.h"
#include "httpd.h"
#include "http_conf_globals.h"
#include "http_log.h"
-#include "http_main.h"
#include "service.h"
#include "registry.h"
#include "ap_mpm.h"
+#include "..\..\modules\mpm\winnt\winnt.h"
typedef void (CALLBACK *ap_completion_t)();
API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
+API_VAR_IMPORT char *ap_server_argv0;
static struct
{
SERVICE_STATUS ssStatus;
FILE *logFile;
char *service_dir;
+ HANDLE threadService;
+ HANDLE threadMonitor;
} globdat;
static void WINAPI service_main_fn(DWORD, LPTSTR *);
static int ap_start_service(SC_HANDLE);
static int ap_stop_service(SC_HANDLE);
-static void CALLBACK report_service95_running()
+static LRESULT CALLBACK MonitorWin9xWndProc(HWND hWnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
{
- FreeConsole();
+/* This is the WndProc procedure for our invisible window.
+ * When the user shuts down the system, this window is sent
+ * a signal WM_ENDSESSION. We clean up by signaling Apache
+ * to shut down, and idle until Apache's primary thread quits.
+ */
+ if ((msg == WM_ENDSESSION) && (lParam != ENDSESSION_LOGOFF))
+ {
+ ap_start_shutdown();
+ if (wParam)
+ WaitForSingleObject(globdat.threadService, 30000);
+ return 0;
+ }
+ return (DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+static DWORD WINAPI MonitorWin9xEvents(LPVOID initEvent)
+{
+/* When running on Windows 9x, the ConsoleCtrlHandler is _NOT_
+ * called when the system is shutdown. So create an invisible
+ * window to watch for the WM_ENDSESSION message, and watch for
+ * the WM_CLOSE message to shut the window down.
+ */
+ WNDCLASS wc;
+ HWND hwndMain;
+
+ wc.style = CS_GLOBALCLASS;
+ wc.lpfnWndProc = MonitorWin9xWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = NULL;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "ApacheWin9xService";
+
+ if (RegisterClass(&wc))
+ {
+ /* Create an invisible window */
+ hwndMain = CreateWindow("ApacheWin9xService", "Apache",
+ WS_OVERLAPPEDWINDOW & ~WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, NULL, NULL);
+ if (hwndMain)
+ {
+ MSG msg;
+ /* If we succeed, eliminate the console window.
+ * Signal the parent we are all set up, and
+ * watch the message queue while the window lives.
+ */
+ FreeConsole();
+ SetEvent((HANDLE) initEvent);
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (msg.message == WM_CLOSE)
+ DestroyWindow(hwndMain);
+ else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ globdat.threadMonitor = 0;
+ return(0);
+ }
+ }
+ /* We failed or are soon to die...
+ * we won't need this much longer
+ */
+ SetEvent((HANDLE) initEvent);
+ globdat.threadMonitor = 0;
+ return(0);
+}
- /* We do this only once, ever */
- ap_mpm_init_complete = NULL;
+static void CALLBACK report_service9x_running()
+{
}
-int service95_main(int (*main_fn)(int, char **), int argc, char **argv )
+int service9x_main(int (*main_fn)(int, char **), int argc, char **argv )
{
- HINSTANCE hkernel;
DWORD (WINAPI *RegisterServiceProcess)(DWORD, DWORD);
+ HINSTANCE hkernel;
+ DWORD threadId;
+
+ globdat.threadService = GetCurrentThread();
/* Obtain a handle to the kernel library */
hkernel = LoadLibrary("KERNEL32.DLL");
- if (!hkernel)
- return -1;
-
- /* Find the RegisterServiceProcess function */
- RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
- GetProcAddress(hkernel, "RegisterServiceProcess");
- if (RegisterServiceProcess == NULL)
- return -1;
-
- /* Register this process as a service */
- if (!RegisterServiceProcess((DWORD)NULL, 1))
- return -1;
-
- /* Eliminate the console for the remainer of the service session */
- ap_mpm_init_complete = report_service95_running;
+ if (hkernel) {
+ /* Find the RegisterServiceProcess function */
+ RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
+ GetProcAddress(hkernel, "RegisterServiceProcess");
+ if (RegisterServiceProcess) {
+ if (RegisterServiceProcess((DWORD)NULL, 1)) {
+ HANDLE installed = CreateEvent(NULL, FALSE, FALSE, NULL);
+ globdat.threadMonitor = CreateThread(NULL, 0,
+ MonitorWin9xEvents,
+ (LPVOID) installed,
+ 0, &threadId);
+ WaitForSingleObject(installed, 30000);
+ CloseHandle(installed);
+ }
+ }
+ }
/* Run the service */
globdat.exit_status = main_fn(argc, argv);
+ /* Still have a thread & window to clean up, so signal now */
+ if (globdat.threadMonitor)
+ {
+ PostThreadMessage(threadId, WM_CLOSE, 0, 0);
+ WaitForSingleObject(globdat.threadMonitor, 30000);
+ }
+
/* When the service quits, remove it from the
system service table */
- RegisterServiceProcess((DWORD)NULL, 0);
+ if (RegisterServiceProcess)
+ RegisterServiceProcess((DWORD)NULL, 0);
/* Free the kernel library */
- // Worthless, methinks, since it won't be reclaimed
- // FreeLibrary(hkernel);
+ if (hkernel)
+ FreeLibrary(hkernel);
- /* We have to quit right here to avoid an invalid page fault */
- // But, this is worth experimenting with!
return (globdat.exit_status);
}
-int service_main(int (*main_fn)(int, char **), int argc, char **argv )
+int servicent_main(int (*main_fn)(int, char **), int argc, char **argv )
{
SERVICE_TABLE_ENTRY dispatchTable[] =
{
}
}
-void service_cd()
-{
- /* change to the drive with the executable */
- char buf[300];
- GetModuleFileName(NULL, buf, 300);
- buf[2] = 0;
- chdir(buf);
-}
-
-static void CALLBACK report_service_started()
+static void CALLBACK report_servicent_started()
{
ReportStatusToSCMgr(
SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0); // wait hint
-
- /* This is only reported once, ever! */
- ap_mpm_init_complete = NULL;
}
void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
NO_ERROR, // exit code
3000); // wait hint
- ap_mpm_init_complete = report_service_started;
-
- service_cd();
+ ap_mpm_init_complete = report_servicent_started;
/* Fetch server_conf from the registry
* Rebuild argv and argc adding the -d server_root and -f server_conf then
{
int state;
-
state = globdat.ssStatus.dwCurrentState;
switch(dwCtrlCode)
{
return(1);
}
-void InstallService(char *display_name, char *conf)
+void InstallServiceNT(char *display_name, char *conf)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
}
-void RemoveService(char *display_name)
+void RemoveServiceNT(char *display_name)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
}
/* Determine is service_name is a valid service
+ * Simplify by testing the registry rather than the SCM
+ * as this will work on both WinNT and Win9x.
*/
-BOOL isValidService(char *display_name) {
- SC_HANDLE schSCM, schSVC;
+BOOL isValidService(ap_pool_t *p, char *display_name) {
char service_name[256];
- int Err;
+ char *service_conf;
/* Remove spaces from display name to create service name */
ap_collapse_spaces(service_name, display_name);
+ if(ap_registry_get_service_conf(p, &service_conf, service_name)) {
+ return TRUE;
+ }
+
+ return FALSE;
+
+#if 0
+ SC_HANDLE schSCM, schSVC;
+ int Err;
+
if (!(schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), NULL,
"OpenSCManager failed");
"OpenService failed");
return FALSE;
+#endif
}
+/* Although the Win9x service enhancement added -k startservice,
+ * it is never processed here, so we still ignore that param.
+ */
int send_signal_to_service(char *display_name, char *sig) {
SC_HANDLE schService;
SC_HANDLE schSCManager;
return TRUE;
return FALSE;
}
-
+
#endif /* WIN32 */