diff options
author | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
---|---|---|
committer | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 03:10:21 -0500 |
commit | c0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch) | |
tree | 5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/httpd-2.0.64/server/mpm/winnt | |
parent | b6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff) |
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2
Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/httpd-2.0.64/server/mpm/winnt')
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c | 697 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def | 10 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp | 103 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h | 57 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c | 1167 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h | 39 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h | 80 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c | 1728 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h | 114 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c | 175 | ||||
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c | 1346 |
11 files changed, 0 insertions, 5516 deletions
diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c deleted file mode 100644 index a352dd1b..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c +++ /dev/null @@ -1,697 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -/* - * Win9xConHook.dll - a hook proc to clean up Win95/98 console behavior. - * - * It is well(?) documented by Microsoft that the Win9x HandlerRoutine - * hooked by the SetConsoleCtrlHandler never receives the CTRL_CLOSE_EVENT, - * CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT signals. - * - * It is possible to have a second window to monitor the WM_ENDSESSION - * message, but the close button still fails.. - * - * There is a 16bit polling method for the close window option, but this - * is CPU intensive and requires thunking. - * - * Attempts to subclass the 'tty' console fail, since that message thread - * is actually owned by the 16 bit winoldap.mod process, although the - * window reports it is owned by the process/thread of the console app. - * - * Win9xConHook is thunks the WM_CLOSE and WM_ENDSESSION messages, - * first through a window hook procedure in the winoldap context, into - * a subclass WndProc, and on to a second hidden monitor window in the - * console application's context that dispatches them to the console app's - * registered HandlerRoutine. - */ - -/* This debugging define turns on output to COM1, although you better init - * the port first (even using hyperterm). It's the only way to catch the - * goings on within system logoff/shutdown. - * #define DBG 1 - */ - -#include <windows.h> - -/* Variables used within any process context: - * hookwndmsg is a shared message to send Win9xConHook signals - * origwndprop is a wndprop atom to store the orig wndproc of the tty - * hookwndprop is a wndprop atom to store the hwnd of the hidden child - * is_service reminds us to unmark this process on the way out - */ -static UINT hookwndmsg = 0; -static LPCTSTR origwndprop; -static LPCTSTR hookwndprop; -static BOOL is_service = 0; -//static HMODULE hmodThis = NULL; - -/* Variables used within the tty processes' context: - * is_tty flags this process; -1 == unknown, 1 == if tty, 0 == if not - * hw_tty is the handle of the top level tty in this process context - * is_subclassed is toggled to assure DllMain removes the subclass on unload - * hmodLock is there to try and prevent this dll from being unloaded if the - * hook is removed while we are subclassed - */ -static int is_tty = -1; -static HWND hwtty = NULL; -static BOOL is_subclassed = 0; - -// This simply causes a gpfault the moment it tries to FreeLibrary within -// the subclass procedure ... not good. -//static HMODULE hmodLock = NULL; - -/* Variables used within the service or console app's context: - * hmodHook is the instance handle of this module for registering the hooks - * hhkGetMessage is the hook handle for catching Posted messages - * hhkGetMessage is the hook handle for catching Sent messages - * monitor_hwnd is the invisible window that handles our tty messages - * the tty_info strucure is used to pass args into the hidden window's thread - */ -static HMODULE hmodHook = NULL; -static HHOOK hhkGetMessage; -//static HHOOK hhkCallWndProc; -static HWND monitor_hwnd = NULL; - -typedef struct { - PHANDLER_ROUTINE phandler; - HINSTANCE instance; - HWND parent; - INT type; - LPCSTR name; -} tty_info; - -/* These are the GetWindowLong offsets for the hidden window's internal info - * gwltty_phandler is the address of the app's HandlerRoutine - * gwltty_ttywnd is the tty this hidden window will handle messages from - */ -#define gwltty_phandler 0 -#define gwltty_ttywnd 4 - -/* Forward declaration prototypes for internal functions - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd); -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service); -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty); -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static int HookProc(int hc, HWND *hwnd, UINT *msg, - WPARAM *wParam, LPARAM *lParam); -#ifdef DBG -static VOID DbgPrintf(LPTSTR fmt, ...); -#endif - - -/* DllMain is invoked by every process in the entire system that is hooked - * by our window hooks, notably the tty processes' context, and by the user - * who wants tty messages (the app). Keep it light and simple. - */ -BOOL __declspec(dllexport) APIENTRY DllMain(HINSTANCE hModule, ULONG ulReason, - LPVOID pctx) -{ - if (ulReason == DLL_PROCESS_ATTACH) - { - //hmodThis = hModule; - if (!hookwndmsg) { - origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc")); - hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd")); - hookwndmsg = RegisterWindowMessage("Win9xConHookMsg"); - } -#ifdef DBG -// DbgPrintf("H ProcessAttach:%8.8x\r\n", -// GetCurrentProcessId()); -#endif - } - else if ( ulReason == DLL_PROCESS_DETACH ) - { -#ifdef DBG -// DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId()); -#endif - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - if (is_subclassed) - SendMessage(hwtty, hookwndmsg, 0, (LPARAM)hwtty); - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - if (hookwndmsg) { - GlobalDeleteAtom((ATOM)origwndprop); - GlobalDeleteAtom((ATOM)hookwndprop); - hookwndmsg = 0; - } - } - return TRUE; -} - - -/* This group of functions are provided for the service/console app - * to register itself a HandlerRoutine to accept tty or service messages - */ - - -/* Exported function that creates a Win9x 'service' via a hidden window, - * that notifies the process via the HandlerRoutine messages. - */ -BOOL __declspec(dllexport) WINAPI Windows9xServiceCtrlHandler( - PHANDLER_ROUTINE phandler, - LPCSTR name) -{ - /* If we have not yet done so */ - FreeConsole(); - - if (name) - { - DWORD tid; - HANDLE hThread; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = NULL; - tty.name = name; - tty.type = 2; - RegisterWindows9xService(TRUE); - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (hThread) - { - CloseHandle(hThread); - return TRUE; - } - } - else /* remove */ - { - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* Exported function that registers a HandlerRoutine to accept missing - * Win9x CTRL_EVENTs from the tty window, as NT does without a hassle. - * If add is 1 or 2, register the handler, if 2 also mark it as a service. - * If add is 0 deregister the handler, and unmark if a service - */ -BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler( - PHANDLER_ROUTINE phandler, - INT add) -{ - HWND parent; - - if (add) - { - HANDLE hThread; - DWORD tid; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - EnumWindows(EnumttyWindow, (LPARAM)&parent); - if (!parent) { -#ifdef DBG - DbgPrintf("A EnumttyWindow failed (%d)\r\n", GetLastError()); -#endif - return FALSE; - } - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = parent; - tty.type = add; - if (add == 2) { - tty.name = "ttyService"; - RegisterWindows9xService(TRUE); - } - else - tty.name = "ttyMonitor"; - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (!hThread) - return FALSE; - CloseHandle(hThread); - hmodHook = LoadLibrary("Win9xConHook.dll"); - if (hmodHook) - { - hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE, - (HOOKPROC)GetProcAddress(hmodHook, "GetMsgProc"), hmodHook, 0); - //hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, - // (HOOKPROC)GetProcAddress(hmodHook, "CallWndProc"), hmodHook, 0); - } - return TRUE; - } - else /* remove */ - { - if (monitor_hwnd) { - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - } - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* The following internal helpers are only used within the app's context - */ - -/* ttyConsoleCreateThread is the process that runs within the user app's - * context. It creates and pumps the messages of a hidden monitor window, - * watching for messages from the system, or the associated subclassed tty - * window. Things can happen in our context that can't be done from the - * tty's context, and visa versa, so the subclass procedure and this hidden - * window work together to make it all happen. - */ -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty) -{ - WNDCLASS wc; - MSG msg; - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = ttyConsoleCtrlWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 8; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (((tty_info*)tty)->parent) - wc.lpszClassName = "ttyConHookChild"; - else - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - - if (!RegisterClass(&wc)) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating class %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, GetLastError()); -#endif - return 0; - } - - /* Create an invisible window */ - monitor_hwnd = CreateWindow(wc.lpszClassName, ((tty_info*)tty)->name, - WS_OVERLAPPED & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, - ((tty_info*)tty)->instance, tty); - - if (!monitor_hwnd) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating window %s %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, - ((tty_info*)tty)->name, GetLastError()); -#endif - return 0; - } - - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Tag again as deleted, just in case we missed WM_DESTROY */ - monitor_hwnd = NULL; - return 0; -} - - -/* This is the WndProc procedure for our invisible window. - * When our subclasssed tty window receives the WM_CLOSE, WM_ENDSESSION, - * or WM_QUERYENDSESSION messages, the message is dispatched to our hidden - * window (this message process), and we call the installed HandlerRoutine - * that was registered by the app. - */ -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_CREATE) - { - tty_info *tty = (tty_info*)(((LPCREATESTRUCT)lParam)->lpCreateParams); - SetWindowLong(hwnd, gwltty_phandler, (LONG)tty->phandler); - SetWindowLong(hwnd, gwltty_ttywnd, (LONG)tty->parent); -#ifdef DBG - DbgPrintf("A proc %8.8x created %8.8x %s for tty wnd %8.8x\r\n", - GetCurrentProcessId(), hwnd, - tty->name, tty->parent); -#endif - if (tty->parent) { - SetProp(tty->parent, hookwndprop, hwnd); - PostMessage(tty->parent, hookwndmsg, - tty->type, (LPARAM)tty->parent); - } - return 0; - } - else if (msg == WM_DESTROY) - { - HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd); -#ifdef DBG - DbgPrintf("A proc %8.8x destroyed %8.8x ttyConHookChild\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (parent) { - RemoveProp(parent, hookwndprop); - SendMessage(parent, hookwndmsg, 0, (LPARAM)parent); - } - monitor_hwnd = NULL; - } - else if (msg == WM_CLOSE) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_CLOSE_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_CLOSE_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return !rv; - } - else if ((msg == WM_QUERYENDSESSION) || (msg == WM_ENDSESSION)) - { - if (lParam & ENDSESSION_LOGOFF) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_LOGOFF_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_LOGOFF_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - else - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_SHUTDOWN_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_SHUTDOWN_EVENT " - "returning %d\r\n", GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - } - return (DefWindowProc(hwnd, msg, wParam, lParam)); -} - - -/* The following internal helpers are invoked by the hooked tty and our app - */ - - -/* Register or deregister the current process as a Windows9x style service. - * Experience shows this call is ignored across processes, so the second - * arg to RegisterServiceProcess (process group id) is effectively useless. - */ -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service) -{ - static HINSTANCE hkernel; - static DWORD (WINAPI *register_service_process)(DWORD, DWORD) = NULL; - BOOL rv; - - if (set_service == is_service) - return 1; - -#ifdef DBG - DbgPrintf("R %s proc %8.8x as a service\r\n", - set_service ? "installing" : "removing", - GetCurrentProcessId()); -#endif - - if (!register_service_process) - { - /* Obtain a handle to the kernel library */ - hkernel = LoadLibrary("KERNEL32.DLL"); - if (!hkernel) - return 0; - - /* Find the RegisterServiceProcess function */ - register_service_process = (DWORD (WINAPI *)(DWORD, DWORD)) - GetProcAddress(hkernel, "RegisterServiceProcess"); - if (register_service_process == NULL) { - FreeLibrary(hkernel); - return 0; - } - } - - /* Register this process as a service */ - rv = register_service_process(0, set_service != FALSE); - if (rv) - is_service = set_service; - - if (!is_service) - { - /* Unload the kernel library */ - FreeLibrary(hkernel); - register_service_process = NULL; - } - return rv; -} - - -/* - * This function only works when this process is the active process - * (e.g. once it is running a child process, it can no longer determine - * which console window is its own.) - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd) -{ - char tmp[8]; - if (GetClassName(wnd, tmp, sizeof(tmp)) && !strcmp(tmp, "tty")) - { - DWORD wndproc, thisproc = GetCurrentProcessId(); - GetWindowThreadProcessId(wnd, &wndproc); - if (wndproc == thisproc) { - *((HWND*)retwnd) = wnd; - return FALSE; - } - } - return TRUE; -} - - -/* The remaining code all executes --in the tty's own process context-- - * - * That means special attention must be paid to what it's doing... - */ - -/* Subclass message process for the tty window - * - * This code -handles- WM_CLOSE, WM_ENDSESSION and WM_QUERYENDSESSION - * by dispatching them to the window identified by the hookwndprop - * property atom set against our window. Messages are then dispatched - * to origwndprop property atom we set against the window when we - * injected this subclass. This trick did not work with simply a hook. - */ -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop); - if (!origproc) - return 0; - - if (msg == WM_NCDESTROY - || (msg == hookwndmsg && !LOWORD(wParam) && (HWND)lParam == hwnd)) - { - if (is_subclassed) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x Subclass removed\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (is_service) - RegisterWindows9xService(FALSE); - SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc); - RemoveProp(hwnd, origwndprop); - RemoveProp(hwnd, hookwndprop); - is_subclassed = FALSE; - //if (hmodLock) - // FreeLibrary(hmodLock); - //hmodLock = NULL; - } - } - else if (msg == WM_CLOSE || msg == WM_ENDSESSION - || msg == WM_QUERYENDSESSION) - { - HWND child = (HWND)GetProp(hwnd, hookwndprop); - if (child) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x forwarded msg:%d\r\n", - GetCurrentProcessId(), hwnd, msg); -#endif - return SendMessage(child, msg, wParam, lParam); - } - } - return CallWindowProc(origproc, hwnd, msg, wParam, lParam); -} - - -/* HookProc, once installed, is responsible for subclassing the system - * tty windows. It generally does nothing special itself, since - * research indicates that it cannot deal well with the messages we are - * interested in, that is, WM_CLOSE, WM_QUERYSHUTDOWN and WM_SHUTDOWN - * of the tty process. - * - * Respond and subclass only when a WM_NULL is received by the window. - */ -int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam) -{ - if (is_tty == -1 && *hwnd) - { - char ttybuf[8]; - HWND htty; - hwtty = *hwnd; - while (htty = GetParent(hwtty)) - hwtty = htty; - is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf)) - && !strcmp(ttybuf, "tty")); -#ifdef DBG - if (is_tty) - DbgPrintf("H proc %08x tracking hwnd %08x\r\n", - GetCurrentProcessId(), hwtty); -#endif - } - - if (*msg == hookwndmsg && *wParam && *lParam == (LPARAM)hwtty && is_tty) - { - WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC); - //char myname[MAX_PATH]; - //if (GetModuleFileName(hmodThis, myname, sizeof(myname))) - // hmodLock = LoadLibrary(myname); - SetProp(hwtty, origwndprop, origproc); - SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc); - is_subclassed = TRUE; -#ifdef DBG - DbgPrintf("H proc %08x hwnd:%08x Subclassed\r\n", - GetCurrentProcessId(), hwtty); -#endif - if (LOWORD(*wParam) == 2) - RegisterWindows9xService(TRUE); - } - - return -1; -} - - -/* - * PostMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK GetMsgProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PMSG pmsg; - - pmsg = (PMSG)lParam; - - if (pmsg) { - int rv = HookProc(hc, &pmsg->hwnd, &pmsg->message, - &pmsg->wParam, &pmsg->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -/* - * SendMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK CallWndProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PCWPSTRUCT pcwps = (PCWPSTRUCT)lParam; - - if (pcwps) { - int rv = HookProc(hc, &pcwps->hwnd, &pcwps->message, - &pcwps->wParam, &pcwps->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -#ifdef DBG -VOID DbgPrintf( - LPTSTR fmt, - ... - ) -{ - static HANDLE mutex; - va_list marker; - TCHAR szBuf[256]; - DWORD t; - HANDLE gDbgOut; - - va_start(marker, fmt); - wvsprintf(szBuf, fmt, marker); - va_end(marker); - - if (!mutex) - mutex = CreateMutex(NULL, FALSE, "Win9xConHookDbgOut"); - WaitForSingleObject(mutex, INFINITE); - gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); - WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL); - CloseHandle(gDbgOut); - ReleaseMutex(mutex); -} -#endif - -#endif /* WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def deleted file mode 100644 index 85ec1664..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.def +++ /dev/null @@ -1,10 +0,0 @@ -LIBRARY Win9xConHook - -EXETYPE WINDOWS - -EXPORTS - DllMain - GetMsgProc - CallWndProc - FixConsoleCtrlHandler - Windows9xServiceCtrlHandler diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp deleted file mode 100644 index 77cbacfc..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.dsp +++ /dev/null @@ -1,103 +0,0 @@ -# Microsoft Developer Studio Project File - Name="Win9xConHook" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=Win9xConHook - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak" CFG="Win9xConHook - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Win9xConHook - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Win9xConHook - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Win9xConHook - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\Release" -# PROP BASE Intermediate_Dir ".\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Release\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" /opt:ref - -!ELSEIF "$(CFG)" == "Win9xConHook - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Debug\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" - -!ENDIF - -# Begin Target - -# Name "Win9xConHook - Win32 Release" -# Name "Win9xConHook - Win32 Debug" -# Begin Source File - -SOURCE=.\Win9xConHook.c -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.def -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.h -# End Source File -# End Target -# End Project diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h deleted file mode 100644 index e3471034..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AP_WIN9XCONHOOK_H -#define AP_WIN9XCONHOOK_H - -#ifdef WIN32 - -/* Windows9xServiceCtrlHandler registers a handler routine, frees the - * console window, and registers this process as a service in Win9x. - * It creats a hidden window of class "ApacheWin95ServiceMonitor" - * and titled by the name passed, which passes the WM_SHUTDOWN message - * through the given HandlerRoutine's CTRL_SHUTDOWN event. - * Call with name of NULL to remove the Service handler. - */ -BOOL WINAPI Windows9xServiceCtrlHandler(PHANDLER_ROUTINE phandler, LPCSTR name); - - -/* FixConsoleControlHandler registers a handler routine with the - * Win9xConHook.dll, creating a hidden window and forwarding the - * WM_ENDSESSION and WM_CLOSE messages to the given HandlerRoutine - * as CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT and CTRL_CLOSE_EVENT. - * The application should still use SetConsoleCtrlHandler to grab - * the CTRL_BREAK_EVENT and CTRL_C_EVENT, if desired. - */ -BOOL WINAPI FixConsoleCtrlHandler(PHANDLER_ROUTINE phandler, BOOL add); - - -/* - * Exported PostMessage Hook, never use this directly: - * - * LRESULT CALLBACK GetMsgProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - - -/* - * Exported SendMessage Hook, never use this directly: - * - * LRESULT CALLBACK CallWndProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - -#endif /* WIN32 */ - -#endif AP_WIN9XCONHOOK_H diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c deleted file mode 100644 index 266d0b3c..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/child.c +++ /dev/null @@ -1,1167 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "apr_portable.h" -#include "apr_thread_proc.h" -#include "apr_getopt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_shm.h" -#include "apr_thread_mutex.h" -#include "ap_mpm.h" -#include "ap_config.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm_winnt.h" -#include "mpm_common.h" -#include <malloc.h> -#include "apr_atomic.h" - -/* shared with mpm_winnt.c */ -extern DWORD my_pid; - -/* used by parent to signal the child to start and exit */ -/* shared with mpm_winnt.c, but should be private to child.c */ -apr_proc_mutex_t *start_mutex; -HANDLE exit_event; - -/* child_main() should never need to modify is_graceful!?! */ -extern int volatile is_graceful; - -/* Queue for managing the passing of COMP_CONTEXTs between - * the accept and worker threads. - */ -static apr_pool_t *pchild; -static int shutdown_in_progress = 0; -static int workers_may_exit = 0; -static unsigned int g_blocked_threads = 0; -static HANDLE max_requests_per_child_event; - -static apr_thread_mutex_t *child_lock; -static apr_thread_mutex_t *qlock; -static PCOMP_CONTEXT qhead = NULL; -static PCOMP_CONTEXT qtail = NULL; -static int num_completion_contexts = 0; -static int max_num_completion_contexts = 0; -static HANDLE ThreadDispatchIOCP = NULL; -static HANDLE qwait_event = NULL; - - -AP_DECLARE(void) mpm_recycle_completion_context(PCOMP_CONTEXT context) -{ - /* Recycle the completion context. - * - clear the ptrans pool - * - put the context on the queue to be consumed by the accept thread - * Note: - * context->accept_socket may be in a disconnected but reusable - * state so -don't- close it. - */ - if (context) { - apr_pool_clear(context->ptrans); - context->ba = apr_bucket_alloc_create(context->ptrans); - context->next = NULL; - ResetEvent(context->Overlapped.hEvent); - apr_thread_mutex_lock(qlock); - if (qtail) { - qtail->next = context; - } else { - qhead = context; - SetEvent(qwait_event); - } - qtail = context; - apr_thread_mutex_unlock(qlock); - } -} - -AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void) -{ - apr_status_t rv; - PCOMP_CONTEXT context = NULL; - - while (1) { - /* Grab a context off the queue */ - apr_thread_mutex_lock(qlock); - if (qhead) { - context = qhead; - qhead = qhead->next; - if (!qhead) - qtail = NULL; - } else { - ResetEvent(qwait_event); - } - apr_thread_mutex_unlock(qlock); - - if (!context) { - /* We failed to grab a context off the queue, consider allocating - * a new one out of the child pool. There may be up to - * (ap_threads_per_child + num_listeners) contexts in the system - * at once. - */ - if (num_completion_contexts >= max_num_completion_contexts) { - /* All workers are busy, need to wait for one */ - static int reported = 0; - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, - "Server ran out of threads to serve requests. Consider " - "raising the ThreadsPerChild setting"); - reported = 1; - } - - /* Wait for a worker to free a context. Once per second, give - * the caller a chance to check for shutdown. If the wait - * succeeds, get the context off the queue. It must be available, - * since there's only one consumer. - */ - rv = WaitForSingleObject(qwait_event, 1000); - if (rv == WAIT_OBJECT_0) - continue; - else /* Hopefully, WAIT_TIMEOUT */ - return NULL; - } else { - /* Allocate another context. - * Note: - * Multiple failures in the next two steps will cause the pchild pool - * to 'leak' storage. I don't think this is worth fixing... - */ - apr_allocator_t *allocator; - - apr_thread_mutex_lock(child_lock); - context = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); - - context->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (context->Overlapped.hEvent == NULL) { - /* Hopefully this is a temporary condition ... */ - ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_os_error(), ap_server_conf, - "mpm_get_completion_context: CreateEvent failed."); - - apr_thread_mutex_unlock(child_lock); - return NULL; - } - - /* Create the tranaction pool */ - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - rv = apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_WARNING, rv, ap_server_conf, - "mpm_get_completion_context: Failed to create the transaction pool."); - CloseHandle(context->Overlapped.hEvent); - - apr_thread_mutex_unlock(child_lock); - return NULL; - } - apr_allocator_owner_set(allocator, context->ptrans); - apr_pool_tag(context->ptrans, "transaction"); - context->accept_socket = INVALID_SOCKET; - context->ba = apr_bucket_alloc_create(context->ptrans); - apr_atomic_inc(&num_completion_contexts); - - apr_thread_mutex_unlock(child_lock); - break; - } - } else { - /* Got a context from the queue */ - break; - } - } - - return context; -} - -AP_DECLARE(apr_status_t) mpm_post_completion_context(PCOMP_CONTEXT context, - io_state_e state) -{ - LPOVERLAPPED pOverlapped; - if (context) - pOverlapped = &context->Overlapped; - else - pOverlapped = NULL; - - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, state, pOverlapped); - return APR_SUCCESS; -} - - -/* - * find_ready_listener() - * Only used by Win9* and should go away when the win9*_accept() function is - * reimplemented using apr_poll(). - */ -static ap_listen_rec *head_listener; - -static APR_INLINE ap_listen_rec *find_ready_listener(fd_set * main_fds) -{ - ap_listen_rec *lr; - SOCKET nsd; - - lr = head_listener; - do { - apr_os_sock_get(&nsd, lr->sd); - if (FD_ISSET(nsd, main_fds)) { - head_listener = lr->next; - if (!head_listener) { - head_listener = ap_listeners; - } - return lr; - } - lr = lr->next; - if (!lr) { - lr = ap_listeners; - } - } while (lr != head_listener); - return NULL; -} - - -/* Windows 9x specific code... - * Accept processing for on Windows 95/98 uses a producer/consumer queue - * model. A single thread accepts connections and queues the accepted socket - * to the accept queue for consumption by a pool of worker threads. - * - * win9x_accept() - * The accept threads runs this function, which accepts connections off - * the network and calls add_job() to queue jobs to the accept_queue. - * add_job()/remove_job() - * Add or remove an accepted socket from the list of sockets - * connected to clients. allowed_globals.jobmutex protects - * against multiple concurrent access to the linked list of jobs. - * win9x_get_connection() - * Calls remove_job() to pull a job from the accept queue. All the worker - * threads block on remove_job. - */ - -typedef struct joblist_s { - struct joblist_s *next; - int sock; -} joblist; - -typedef struct globals_s { - HANDLE jobsemaphore; - joblist *jobhead; - joblist *jobtail; - apr_thread_mutex_t *jobmutex; - int jobcount; -} globals; - -globals allowed_globals = {NULL, NULL, NULL, NULL, 0}; - -#define MAX_SELECT_ERRORS 100 - - -static void add_job(int sock) -{ - joblist *new_job; - - new_job = (joblist *) malloc(sizeof(joblist)); - if (new_job == NULL) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Ouch! Out of memory in add_job()!"); - return; - } - new_job->next = NULL; - new_job->sock = sock; - - apr_thread_mutex_lock(allowed_globals.jobmutex); - - if (allowed_globals.jobtail != NULL) - allowed_globals.jobtail->next = new_job; - allowed_globals.jobtail = new_job; - if (!allowed_globals.jobhead) - allowed_globals.jobhead = new_job; - allowed_globals.jobcount++; - ReleaseSemaphore(allowed_globals.jobsemaphore, 1, NULL); - - apr_thread_mutex_unlock(allowed_globals.jobmutex); -} - - -static int remove_job(void) -{ - joblist *job; - int sock; - - WaitForSingleObject(allowed_globals.jobsemaphore, INFINITE); - apr_thread_mutex_lock(allowed_globals.jobmutex); - - if (shutdown_in_progress && !allowed_globals.jobhead) { - apr_thread_mutex_unlock(allowed_globals.jobmutex); - return (INVALID_SOCKET); - } - job = allowed_globals.jobhead; - ap_assert(job); - allowed_globals.jobhead = job->next; - if (allowed_globals.jobhead == NULL) - allowed_globals.jobtail = NULL; - apr_thread_mutex_unlock(allowed_globals.jobmutex); - sock = job->sock; - free(job); - - return (sock); -} - - -static unsigned int __stdcall win9x_accept(void * dummy) -{ - struct timeval tv; - fd_set main_fds; - int wait_time = 1; - int csd; - SOCKET nsd = INVALID_SOCKET; - struct sockaddr_in sa_client; - int count_select_errors = 0; - int rc; - int clen; - ap_listen_rec *lr; - struct fd_set listenfds; - SOCKET listenmaxfd = INVALID_SOCKET; - - /* Setup the listeners - * ToDo: Use apr_poll() - */ - FD_ZERO(&listenfds); - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - apr_os_sock_get(&nsd, lr->sd); - FD_SET(nsd, &listenfds); - if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) { - listenmaxfd = nsd; - } - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Child %d: Listening on port %d.", my_pid, lr->bind_addr->port); - } - } - - head_listener = ap_listeners; - - while (!shutdown_in_progress) { - tv.tv_sec = wait_time; - tv.tv_usec = 0; - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - - rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); - - if (rc == 0 || (rc == SOCKET_ERROR && APR_STATUS_IS_EINTR(apr_get_netos_error()))) { - count_select_errors = 0; /* reset count of errors */ - continue; - } - else if (rc == SOCKET_ERROR) { - /* A "real" error occurred, log it and increment the count of - * select errors. This count is used to ensure we don't go into - * a busy loop of continuous errors. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, apr_get_netos_error(), ap_server_conf, - "select failed with error %d", apr_get_netos_error()); - count_select_errors++; - if (count_select_errors > MAX_SELECT_ERRORS) { - shutdown_in_progress = 1; - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf, - "Too many errors in select loop. Child process exiting."); - break; - } - } else { - ap_listen_rec *lr; - - lr = find_ready_listener(&main_fds); - if (lr != NULL) { - /* fetch the native socket descriptor */ - apr_os_sock_get(&nsd, lr->sd); - } - } - - do { - clen = sizeof(sa_client); - csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); - } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error())); - - if (csd < 0) { - if (APR_STATUS_IS_ECONNABORTED(apr_get_netos_error())) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf, - "accept: (client socket)"); - } - } - else { - add_job(csd); - } - } - SetEvent(exit_event); - return 0; -} - - -static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) -{ - apr_os_sock_info_t sockinfo; - int len; - - if (context == NULL) { - /* allocate the completion context and the transaction pool */ - apr_allocator_t *allocator; - apr_thread_mutex_lock(child_lock); - context = apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); - apr_allocator_create(&allocator); - apr_allocator_max_free_set(allocator, ap_max_mem_free); - apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); - apr_allocator_owner_set(allocator, context->ptrans); - apr_pool_tag(context->ptrans, "transaction"); - apr_thread_mutex_unlock(child_lock); - } - - while (1) { - apr_pool_clear(context->ptrans); - context->ba = apr_bucket_alloc_create(context->ptrans); - context->accept_socket = remove_job(); - if (context->accept_socket == INVALID_SOCKET) { - return NULL; - } - len = sizeof(struct sockaddr); - context->sa_server = apr_palloc(context->ptrans, len); - if (getsockname(context->accept_socket, - context->sa_server, &len)== SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getsockname failed"); - continue; - } - len = sizeof(struct sockaddr); - context->sa_client = apr_palloc(context->ptrans, len); - if ((getpeername(context->accept_socket, - context->sa_client, &len)) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "getpeername failed"); - memset(&context->sa_client, '\0', sizeof(context->sa_client)); - } - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - return context; - } -} - - -/* Windows NT/2000 specific code... - * Accept processing for on Windows NT uses a producer/consumer queue - * model. An accept thread accepts connections off the network then issues - * PostQueuedCompletionStatus() to awake a thread blocked on the ThreadDispatch - * IOCompletionPort. - * - * winnt_accept() - * One or more accept threads run in this function, each of which accepts - * connections off the network and calls PostQueuedCompletionStatus() to - * queue an io completion packet to the ThreadDispatch IOCompletionPort. - * winnt_get_connection() - * Worker threads block on the ThreadDispatch IOCompletionPort awaiting - * connections to service. - */ -#define MAX_ACCEPTEX_ERR_COUNT 250 -static unsigned int __stdcall winnt_accept(void *lr_) -{ - ap_listen_rec *lr = (ap_listen_rec *)lr_; - apr_os_sock_info_t sockinfo; - PCOMP_CONTEXT context = NULL; - DWORD BytesRead; - SOCKET nlsd; - int rv, err_count = 0; - - apr_os_sock_get(&nlsd, lr->sd); - - while (!shutdown_in_progress) { - if (!context) { - context = mpm_get_completion_context(); - if (!context) { - /* Temporary resource constraint? */ - Sleep(0); - continue; - } - } - - /* Create and initialize the accept socket */ - if (context->accept_socket == INVALID_SOCKET) { - context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (context->accept_socket == INVALID_SOCKET) { - /* Another temporary condition? */ - ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "winnt_accept: Failed to allocate an accept socket. " - "Temporary resource constraint? Try again."); - Sleep(100); - continue; - } - } - - /* AcceptEx on the completion context. The completion context will be - * signaled when a connection is accepted. - */ - if (!AcceptEx(nlsd, context->accept_socket, - context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &BytesRead, - &context->Overlapped)) { - rv = apr_get_netos_error(); - if ((rv == APR_FROM_OS_ERROR(WSAEINVAL)) || - (rv == APR_FROM_OS_ERROR(WSAENOTSOCK))) { - /* We can get here when: - * 1) the client disconnects early - * 2) TransmitFile does not properly recycle the accept socket (typically - * because the client disconnected) - * 3) there is VPN or Firewall software installed with buggy AcceptEx implementation - * 4) the webserver is using a dynamic address that has changed - */ - ++err_count; - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - if (err_count > MAX_ACCEPTEX_ERR_COUNT) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Child %d: Encountered too many errors accepting client connections. " - "Possible causes: dynamic address renewal, or incompatible VPN or firewall software. " - "Try using the Win32DisableAcceptEx directive.", my_pid); - err_count = 0; - } - continue; - } - else if ((rv != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) && - (rv != APR_FROM_OS_ERROR(WSA_IO_PENDING))) { - ++err_count; - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - if (err_count > MAX_ACCEPTEX_ERR_COUNT) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "Child %d: Encountered too many errors accepting client connections. " - "Possible causes: Unknown. " - "Try using the Win32DisableAcceptEx directive.", my_pid); - err_count = 0; - } - continue; - } - - /* Wait for pending i/o. - * Wake up once per second to check for shutdown . - * XXX: We should be waiting on exit_event instead of polling - */ - while (1) { - rv = WaitForSingleObject(context->Overlapped.hEvent, 1000); - if (rv == WAIT_OBJECT_0) { - if (context->accept_socket == INVALID_SOCKET) { - /* socket already closed */ - break; - } - if (!GetOverlappedResult((HANDLE)context->accept_socket, - &context->Overlapped, - &BytesRead, FALSE)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, - apr_get_os_error(), ap_server_conf, - "winnt_accept: Asynchronous AcceptEx failed."); - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - } - break; - } - /* WAIT_TIMEOUT */ - if (shutdown_in_progress) { - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - break; - } - } - if (context->accept_socket == INVALID_SOCKET) { - continue; - } - } - - err_count = 0; - /* Inherit the listen socket settings. Required for - * shutdown() to work - */ - if (setsockopt(context->accept_socket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd, - sizeof(nlsd))) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf, - "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed."); - /* Not a failure condition. Keep running. */ - } - - /* Get the local & remote address */ - GetAcceptExSockaddrs(context->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &context->sa_server, - &context->sa_server_len, - &context->sa_client, - &context->sa_client_len); - - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - /* When a connection is received, send an io completion notification to - * the ThreadDispatchIOCP. This function could be replaced by - * mpm_post_completion_context(), but why do an extra function call... - */ - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_CONNECTION_ACCEPTED, - &context->Overlapped); - context = NULL; - } - if (!shutdown_in_progress) { - /* Yow, hit an irrecoverable error! Tell the child to die. */ - SetEvent(exit_event); - } - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Child %d: Accept thread exiting.", my_pid); - return 0; -} - - -static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context) -{ - int rc; - DWORD BytesRead; - DWORD CompKey; - LPOVERLAPPED pol; - - mpm_recycle_completion_context(context); - - apr_atomic_inc(&g_blocked_threads); - while (1) { - if (workers_may_exit) { - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - rc = GetQueuedCompletionStatus(ThreadDispatchIOCP, &BytesRead, &CompKey, - &pol, INFINITE); - if (!rc) { - rc = apr_get_os_error(); - ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, ap_server_conf, - "Child %d: GetQueuedComplationStatus returned %d", my_pid, rc); - continue; - } - - switch (CompKey) { - case IOCP_CONNECTION_ACCEPTED: - context = CONTAINING_RECORD(pol, COMP_CONTEXT, Overlapped); - break; - case IOCP_SHUTDOWN: - apr_atomic_dec(&g_blocked_threads); - return NULL; - default: - apr_atomic_dec(&g_blocked_threads); - return NULL; - } - break; - } - apr_atomic_dec(&g_blocked_threads); - - return context; -} - - -/* - * worker_main() - * Main entry point for the worker threads. Worker threads block in - * win*_get_connection() awaiting a connection to service. - */ -static unsigned int __stdcall worker_main(void *thread_num_val) -{ - static int requests_this_child = 0; - PCOMP_CONTEXT context = NULL; - int thread_num = (int)thread_num_val; - ap_sb_handle_t *sbh; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, - "Child %d: Worker thread %ld starting.", my_pid, thread_num); - while (1) { - conn_rec *c; - apr_int32_t disconnected; - - ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL); - - /* Grab a connection off the network */ - if (use_acceptex) { - context = winnt_get_connection(context); - } - else { - context = win9x_get_connection(context); - } - if (!context) { - /* Time for the thread to exit */ - break; - } - - /* Have we hit MaxRequestPerChild connections? */ - if (ap_max_requests_per_child) { - requests_this_child++; - if (requests_this_child > ap_max_requests_per_child) { - SetEvent(max_requests_per_child_event); - } - } - - ap_create_sb_handle(&sbh, context->ptrans, 0, thread_num); - c = ap_run_create_connection(context->ptrans, ap_server_conf, - context->sock, thread_num, sbh, - context->ba); - - if (c) { - ap_process_connection(c, context->sock); - apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, - &disconnected); - if (!disconnected) { - context->accept_socket = INVALID_SOCKET; - ap_lingering_close(c); - } - else if (!use_acceptex) { - /* If the socket is disconnected but we are not using acceptex, - * we cannot reuse the socket. Disconnected sockets are removed - * from the apr_socket_t struct by apr_sendfile() to prevent the - * socket descriptor from being inadvertently closed by a call - * to apr_socket_close(), so close it directly. - */ - closesocket(context->accept_socket); - context->accept_socket = INVALID_SOCKET; - } - } - else { - /* ap_run_create_connection closes the socket on failure */ - context->accept_socket = INVALID_SOCKET; - } - } - - ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD, - (request_rec *) NULL); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, - "Child %d: Worker thread %ld exiting.", my_pid, thread_num); - return 0; -} - - -static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean) -{ - int i; - - CloseHandle(handles[thread_to_clean]); - for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++) - handles[i] = handles[i + 1]; - (*thread_cnt)--; -} - - -/* - * child_main() - * Entry point for the main control thread for the child process. - * This thread creates the accept thread, worker threads and - * monitors the child process for maintenance and shutdown - * events. - */ -static void create_listener_thread() -{ - int tid; - int num_listeners = 0; - if (!use_acceptex) { - _beginthreadex(NULL, 0, win9x_accept, - NULL, 0, &tid); - } else { - /* Start an accept thread per listener - * XXX: Why would we have a NULL sd in our listeners? - */ - ap_listen_rec *lr; - - /* Number of completion_contexts allowed in the system is - * (ap_threads_per_child + num_listeners). We need the additional - * completion contexts to prevent server hangs when ThreadsPerChild - * is configured to something less than or equal to the number - * of listeners. This is not a usual case, but people have - * encountered it. - * */ - for (lr = ap_listeners; lr ; lr = lr->next) { - num_listeners++; - } - max_num_completion_contexts = ap_threads_per_child + num_listeners; - - /* Now start a thread per listener */ - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - _beginthreadex(NULL, 1000, winnt_accept, - (void *) lr, 0, &tid); - } - } - } -} - - -void child_main(apr_pool_t *pconf) -{ - apr_status_t status; - apr_hash_t *ht; - ap_listen_rec *lr; - HANDLE child_events[2]; - HANDLE *child_handles; - int listener_started = 0; - int threads_created = 0; - int watch_thread; - int time_remains; - int cld; - int tid; - int rv; - int i; - - apr_pool_create(&pchild, pconf); - apr_pool_tag(pchild, "pchild"); - - ap_run_child_init(pchild, ap_server_conf); - ht = apr_hash_make(pchild); - - /* Initialize the child_events */ - max_requests_per_child_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!max_requests_per_child_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Failed to create a max_requests event.", my_pid); - exit(APEXIT_CHILDINIT); - } - child_events[0] = exit_event; - child_events[1] = max_requests_per_child_event; - - allowed_globals.jobsemaphore = CreateSemaphore(NULL, 0, 1000000, NULL); - apr_thread_mutex_create(&allowed_globals.jobmutex, - APR_THREAD_MUTEX_DEFAULT, pchild); - - /* - * Wait until we have permission to start accepting connections. - * start_mutex is used to ensure that only one child ever - * goes into the listen/accept loop at once. - */ - status = apr_proc_mutex_lock(start_mutex); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, status, ap_server_conf, - "Child %d: Failed to acquire the start_mutex. Process will exit.", my_pid); - exit(APEXIT_CHILDINIT); - } - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Acquired the start mutex.", my_pid); - - /* - * Create the worker thread dispatch IOCompletionPort - * on Windows NT/2000 - */ - if (use_acceptex) { - /* Create the worker thread dispatch IOCP */ - ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, - NULL, - 0, - 0); /* CONCURRENT ACTIVE THREADS */ - apr_thread_mutex_create(&qlock, APR_THREAD_MUTEX_DEFAULT, pchild); - qwait_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!qwait_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Failed to create a qwait event.", my_pid); - exit(APEXIT_CHILDINIT); - } - } - - /* - * Create the pool of worker threads - */ - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Starting %d worker threads.", my_pid, ap_threads_per_child); - child_handles = (HANDLE) apr_pcalloc(pchild, ap_threads_per_child * sizeof(int)); - apr_thread_mutex_create(&child_lock, APR_THREAD_MUTEX_DEFAULT, pchild); - - while (1) { - for (i = 0; i < ap_threads_per_child; i++) { - int *score_idx; - int status = ap_scoreboard_image->servers[0][i].status; - if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { - continue; - } - ap_update_child_status_from_indexes(0, i, SERVER_STARTING, NULL); - child_handles[i] = (HANDLE) _beginthreadex(NULL, 0, worker_main, - (void *) i, 0, &tid); - if (child_handles[i] == 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: _beginthreadex failed. Unable to create all worker threads. " - "Created %d of the %d threads requested with the ThreadsPerChild configuration directive.", - my_pid, threads_created, ap_threads_per_child); - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - goto shutdown; - } - threads_created++; - /* Save the score board index in ht keyed to the thread handle. We need this - * when cleaning up threads down below... - */ - apr_thread_mutex_lock(child_lock); - score_idx = apr_pcalloc(pchild, sizeof(int)); - *score_idx = i; - apr_hash_set(ht, &child_handles[i], sizeof(HANDLE), score_idx); - apr_thread_mutex_unlock(child_lock); - } - /* Start the listener only when workers are available */ - if (!listener_started && threads_created) { - create_listener_thread(); - listener_started = 1; - winnt_mpm_state = AP_MPMQ_RUNNING; - } - if (threads_created == ap_threads_per_child) { - break; - } - /* Check to see if the child has been told to exit */ - if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) { - break; - } - /* wait for previous generation to clean up an entry in the scoreboard */ - apr_sleep(1 * APR_USEC_PER_SEC); - } - - /* Wait for one of three events: - * exit_event: - * The exit_event is signaled by the parent process to notify - * the child that it is time to exit. - * - * max_requests_per_child_event: - * This event is signaled by the worker threads to indicate that - * the process has handled MaxRequestsPerChild connections. - * - * TIMEOUT: - * To do periodic maintenance on the server (check for thread exits, - * number of completion contexts, etc.) - * - * XXX: thread exits *aren't* being checked. - * - * XXX: other_child - we need the process handles to the other children - * in order to map them to apr_proc_other_child_read (which is not - * named well, it's more like a_p_o_c_died.) - * - * XXX: however - if we get a_p_o_c handle inheritance working, and - * the parent process creates other children and passes the pipes - * to our worker processes, then we have no business doing such - * things in the child_main loop, but should happen in master_main. - */ - while (1) { -#if !APR_HAS_OTHER_CHILD - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; -#else - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_TIMEOUT) { - apr_proc_other_child_check(); - } - else -#endif - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: WAIT_FAILED -- shutting down server", my_pid); - break; - } - else if (cld == 0) { - /* Exit event was signaled */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Exit event signaled. Child process is ending.", my_pid); - break; - } - else { - /* MaxRequestsPerChild event set by the worker threads. - * Signal the parent to restart - */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Process exiting because it reached " - "MaxRequestsPerChild. Signaling the parent to " - "restart a new child process.", my_pid); - ap_signal_parent(SIGNAL_PARENT_RESTART); - break; - } - } - - /* - * Time to shutdown the child process - */ - - shutdown: - - winnt_mpm_state = AP_MPMQ_STOPPING; - /* Setting is_graceful will cause threads handling keep-alive connections - * to close the connection after handling the current request. - */ - is_graceful = 1; - - /* Close the listening sockets. Note, we must close the listeners - * before closing any accept sockets pending in AcceptEx to prevent - * memory leaks in the kernel. - */ - for (lr = ap_listeners; lr ; lr = lr->next) { - apr_socket_close(lr->sd); - } - - /* Shutdown listener threads and pending AcceptEx socksts - * but allow the worker threads to continue consuming from - * the queue of accepted connections. - */ - shutdown_in_progress = 1; - - Sleep(1000); - - /* Tell the worker threads to exit */ - workers_may_exit = 1; - - /* Release the start_mutex to let the new process (in the restart - * scenario) a chance to begin accepting and servicing requests - */ - rv = apr_proc_mutex_unlock(start_mutex); - if (rv == APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, rv, ap_server_conf, - "Child %d: Released the start mutex", my_pid); - } - else { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "Child %d: Failure releasing the start mutex", my_pid); - } - - /* Shutdown the worker threads */ - if (!use_acceptex) { - for (i = 0; i < threads_created; i++) { - add_job(INVALID_SOCKET); - } - } - else { /* Windows NT/2000 */ - /* Post worker threads blocked on the ThreadDispatch IOCompletion port */ - while (g_blocked_threads > 0) { - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Child %d: %d threads blocked on the completion port", my_pid, g_blocked_threads); - for (i=g_blocked_threads; i > 0; i--) { - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL); - } - Sleep(1000); - } - /* Empty the accept queue of completion contexts */ - apr_thread_mutex_lock(qlock); - while (qhead) { - CloseHandle(qhead->Overlapped.hEvent); - closesocket(qhead->accept_socket); - qhead = qhead->next; - } - apr_thread_mutex_unlock(qlock); - } - - /* Give busy threads a chance to service their connections, - * (no more than the global server timeout period which - * we track in msec remaining). - */ - watch_thread = 0; - time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000)); - - while (threads_created) - { - int nFailsafe = MAXIMUM_WAIT_OBJECTS; - DWORD dwRet; - - /* Every time we roll over to wait on the first group - * of MAXIMUM_WAIT_OBJECTS threads, take a breather, - * and infrequently update the error log. - */ - if (watch_thread >= threads_created) { - if ((time_remains -= 100) < 0) - break; - - /* Every 30 seconds give an update */ - if ((time_remains % 30000) == 0) { - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, - ap_server_conf, - "Child %d: Waiting %d more seconds " - "for %d worker threads to finish.", - my_pid, time_remains / 1000, threads_created); - } - /* We'll poll from the top, 10 times per second */ - Sleep(100); - watch_thread = 0; - } - - /* Fairness, on each iteration we will pick up with the thread - * after the one we just removed, even if it's a single thread. - * We don't block here. - */ - dwRet = WaitForMultipleObjects(min(threads_created - watch_thread, - MAXIMUM_WAIT_OBJECTS), - child_handles + watch_thread, 0, 0); - - if (dwRet == WAIT_FAILED) { - break; - } - if (dwRet == WAIT_TIMEOUT) { - /* none ready */ - watch_thread += MAXIMUM_WAIT_OBJECTS; - continue; - } - else if (dwRet >= WAIT_ABANDONED_0) { - /* We just got the ownership of the object, which - * should happen at most MAXIMUM_WAIT_OBJECTS times. - * It does NOT mean that the object is signaled. - */ - if ((nFailsafe--) < 1) - break; - } - else { - watch_thread += (dwRet - WAIT_OBJECT_0); - if (watch_thread >= threads_created) - break; - cleanup_thread(child_handles, &threads_created, watch_thread); - } - } - - /* Kill remaining threads off the hard way */ - if (threads_created) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Terminating %d threads that failed to exit.", - my_pid, threads_created); - } - for (i = 0; i < threads_created; i++) { - int *score_idx; - TerminateThread(child_handles[i], 1); - CloseHandle(child_handles[i]); - /* Reset the scoreboard entry for the thread we just whacked */ - score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); - ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); - } - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: All worker threads have exited.", my_pid); - - CloseHandle(allowed_globals.jobsemaphore); - apr_thread_mutex_destroy(allowed_globals.jobmutex); - apr_thread_mutex_destroy(child_lock); - - if (use_acceptex) { - apr_thread_mutex_destroy(qlock); - CloseHandle(qwait_event); - } - - apr_pool_destroy(pchild); - CloseHandle(exit_event); -} - -#endif /* def WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h deleted file mode 100644 index 2cae7a8e..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_H -#define APACHE_MPM_H - -/* mpm.h is the place to make declarations that are MPM specific but that must be - * shared with non-mpm specific code in the server. Hummm, perhaps we can - * move most of this stuff to mpm_common.h? - */ - -#include "scoreboard.h" - -#define MPM_NAME "WinNT" - -#define AP_MPM_WANT_SET_PIDFILE -#define AP_MPM_WANT_SET_MAX_REQUESTS -#define AP_MPM_WANT_SET_COREDUMPDIR -#define AP_MPM_WANT_SET_SCOREBOARD -#define AP_MPM_WANT_SET_MAX_MEM_FREE - -extern int ap_threads_per_child; -extern int ap_thread_limit; -extern server_rec *ap_server_conf; - -#endif /* APACHE_MPM_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h deleted file mode 100644 index 847bd732..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_default.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* Default limit on the maximum setting of the ThreadsPerChild configuration - * directive. This limit can be overridden with the ThreadLimit directive. - * This limit directly influences the amount of shared storage that is allocated - * for the scoreboard. DEFAULT_THREAD_LIMIT represents a good compromise - * between scoreboard size and the ability of the server to handle the most - * common installation requirements. - */ -#ifndef DEFAULT_THREAD_LIMIT -#define DEFAULT_THREAD_LIMIT 1920 -#endif - -/* The ThreadLimit directive can be used to override the DEFAULT_THREAD_LIMIT. - * ThreadLimit cannot be tuned larger than MAX_THREAD_LIMIT. - * This is a sort of compile-time limit to help catch typos. - */ -#ifndef MAX_THREAD_LIMIT -#define MAX_THREAD_LIMIT 15000 -#endif - -/* Number of threads started in the child process in the absence - * of a ThreadsPerChild configuration directive - */ -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 64 -#endif - -/* Max number of child processes allowed. - */ -#define HARD_SERVER_LIMIT 1 - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 1 -#endif - -/* Check for definition of DEFAULT_REL_RUNTIMEDIR */ -#ifndef DEFAULT_REL_RUNTIMEDIR -#define DEFAULT_REL_RUNTIMEDIR "logs" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 0 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c deleted file mode 100644 index 6fc0ae60..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef WIN32 - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "apr_portable.h" -#include "apr_thread_proc.h" -#include "apr_getopt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_shm.h" -#include "apr_thread_mutex.h" -#include "ap_mpm.h" -#include "ap_config.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm_winnt.h" -#include "mpm_common.h" -#include <malloc.h> -#include "apr_atomic.h" - - -/* scoreboard.c does the heavy lifting; all we do is create the child - * score by moving a handle down the pipe into the child's stdin. - */ -extern apr_shm_t *ap_scoreboard_shm; -server_rec *ap_server_conf; - -/* Definitions of WINNT MPM specific config globals */ -static HANDLE shutdown_event; /* used to signal the parent to shutdown */ -static HANDLE restart_event; /* used to signal the parent to restart */ - -static char ap_coredump_dir[MAX_STRING_LEN]; - -static int one_process = 0; -static char const* signal_arg = NULL; - -OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */ - -static DWORD parent_pid; -DWORD my_pid; - -int ap_threads_per_child = 0; -int use_acceptex = 1; -static int thread_limit = DEFAULT_THREAD_LIMIT; -static int first_thread_limit = 0; -static int changed_limit_at_restart; -int winnt_mpm_state = AP_MPMQ_STARTING; -/* ap_my_generation are used by the scoreboard code */ -ap_generation_t volatile ap_my_generation=0; - - -/* shared by service.c as global, although - * perhaps it should be private. - */ -apr_pool_t *pconf; - - -/* definitions from child.c */ -void child_main(apr_pool_t *pconf); - -/* used by parent to signal the child to start and exit - * NOTE: these are not sophisticated enough for multiple children - * so they ultimately should not be shared with child.c - */ -extern apr_proc_mutex_t *start_mutex; -extern HANDLE exit_event; - -/* Only one of these, the pipe from our parent, ment only for - * one child worker's consumption (not to be inherited!) - * XXX: decorate this name for the trunk branch, was left simplified - * only to make the 2.2 patch trivial to read. - */ -static HANDLE pipe; - -/* Stub functions until this MPM supports the connection status API */ - -AP_DECLARE(void) ap_update_connection_status(long conn_id, const char *key, \ - const char *value) -{ - /* NOP */ -} - -AP_DECLARE(void) ap_reset_connection_status(long conn_id) -{ - /* NOP */ -} - -AP_DECLARE(apr_array_header_t *) ap_get_status_table(apr_pool_t *p) -{ - /* NOP */ - return NULL; -} - -/* - * Command processors - */ - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_per_child = atoi(arg); - if (ap_threads_per_child > thread_limit) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " - "value of %d threads,", ap_threads_per_child, - thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - " see the", thread_limit); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " ThreadLimit directive."); - ap_threads_per_child = thread_limit; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} -static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - int tmp_thread_limit; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - tmp_thread_limit = atoi(arg); - /* you cannot change ThreadLimit across a restart; ignore - * any such attempts - */ - if (first_thread_limit && - tmp_thread_limit != thread_limit) { - /* how do we log a message? the error log is a bit bucket at this - * point; we'll just have to set a flag so that ap_mpm_run() - * logs a warning later - */ - changed_limit_at_restart = 1; - return NULL; - } - thread_limit = tmp_thread_limit; - - if (thread_limit > MAX_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: ThreadLimit of %d exceeds compile time limit " - "of %d threads,", thread_limit, MAX_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); - thread_limit = MAX_THREAD_LIMIT; - } - else if (thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "WARNING: Require ThreadLimit > 0, setting to 1"); - thread_limit = 1; - } - return NULL; -} -static const char *set_disable_acceptex(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - if (use_acceptex) { - use_acceptex = 0; - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, - "Disabled use of AcceptEx() WinSock2 API"); - } - return NULL; -} - -static const command_rec winnt_cmds[] = { -LISTEN_COMMANDS, -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates" ), -AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, - "Maximum worker threads in a server for this run of Apache"), -AP_INIT_NO_ARGS("Win32DisableAcceptEx", set_disable_acceptex, NULL, RSRC_CONF, - "Disable use of the high performance AcceptEx WinSock2 API to work around buggy VPN or Firewall software"), -{ NULL } -}; - - -/* - * Signalling Apache on NT. - * - * Under Unix, Apache can be told to shutdown or restart by sending various - * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so - * we use "events" instead. The parent apache process goes into a loop - * where it waits forever for a set of events. Two of those events are - * called - * - * apPID_shutdown - * apPID_restart - * - * (where PID is the PID of the apache parent process). When one of these - * is signalled, the Apache parent performs the appropriate action. The events - * can become signalled through internal Apache methods (e.g. if the child - * finds a fatal error and needs to kill its parent), via the service - * control manager (the control thread will signal the shutdown event when - * requested to stop the Apache service), from the -k Apache command line, - * or from any external program which finds the Apache PID from the - * httpd.pid file. - * - * The signal_parent() function, below, is used to signal one of these events. - * It can be called by any child or parent process, since it does not - * rely on global variables. - * - * On entry, type gives the event to signal. 0 means shutdown, 1 means - * graceful restart. - */ -/* - * Initialise the signal names, in the global variables signal_name_prefix, - * signal_restart_name and signal_shutdown_name. - */ -#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */ -char signal_name_prefix[MAX_SIGNAL_NAME]; -char signal_restart_name[MAX_SIGNAL_NAME]; -char signal_shutdown_name[MAX_SIGNAL_NAME]; -void setup_signal_names(char *prefix) -{ - apr_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); - apr_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), - "%s_shutdown", signal_name_prefix); - apr_snprintf(signal_restart_name, sizeof(signal_restart_name), - "%s_restart", signal_name_prefix); -} - -int volatile is_graceful = 0; - -AP_DECLARE(int) ap_graceful_stop_signalled(void) -{ - return is_graceful; -} - -AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type) -{ - HANDLE e; - char *signal_name; - - if (parent_pid == my_pid) { - switch(type) { - case SIGNAL_PARENT_SHUTDOWN: - { - SetEvent(shutdown_event); - break; - } - /* This MPM supports only graceful restarts right now */ - case SIGNAL_PARENT_RESTART: - case SIGNAL_PARENT_RESTART_GRACEFUL: - { - is_graceful = 1; - SetEvent(restart_event); - break; - } - } - return; - } - - switch(type) { - case SIGNAL_PARENT_SHUTDOWN: - { - signal_name = signal_shutdown_name; - break; - } - /* This MPM supports only graceful restarts right now */ - case SIGNAL_PARENT_RESTART: - case SIGNAL_PARENT_RESTART_GRACEFUL: - { - signal_name = signal_restart_name; - is_graceful = 1; - break; - } - default: - return; - } - - e = OpenEvent(EVENT_MODIFY_STATE, FALSE, signal_name); - if (!e) { - /* Um, problem, can't signal the parent, which means we can't - * signal ourselves to die. Ignore for now... - */ - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, - "OpenEvent on %s event", signal_name); - return; - } - if (SetEvent(e) == 0) { - /* Same problem as above */ - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, - "SetEvent on %s event", signal_name); - CloseHandle(e); - return; - } - CloseHandle(e); -} - - -/* - * Passed the following handles [in sync with send_handles_to_child()] - * - * ready event [signal the parent immediately, then close] - * exit event [save to poll later] - * start mutex [signal from the parent to begin accept()] - * scoreboard shm handle [to recreate the ap_scoreboard] - */ -void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event, - apr_proc_mutex_t **child_start_mutex, - apr_shm_t **scoreboard_shm) -{ - HANDLE hScore; - HANDLE ready_event; - HANDLE os_start; - DWORD BytesRead; - void *sb_shared; - apr_status_t rv; - - /* *** We now do this was back in winnt_rewrite_args - * pipe = GetStdHandle(STD_INPUT_HANDLE); - */ - if (!ReadFile(pipe, &ready_event, sizeof(HANDLE), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(HANDLE))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the ready event from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - SetEvent(ready_event); - CloseHandle(ready_event); - - if (!ReadFile(pipe, child_exit_event, sizeof(HANDLE), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(HANDLE))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the exit event from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (!ReadFile(pipe, &os_start, sizeof(os_start), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(os_start))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the start_mutex from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - *child_start_mutex = NULL; - if ((rv = apr_os_proc_mutex_put(child_start_mutex, &os_start, s->process->pool)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Child %d: Unable to access the start_mutex from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (!ReadFile(pipe, &hScore, sizeof(hScore), - &BytesRead, (LPOVERLAPPED) NULL) - || (BytesRead != sizeof(hScore))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Child %d: Unable to retrieve the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - *scoreboard_shm = NULL; - if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Child %d: Unable to access the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - - rv = ap_reopen_scoreboard(s->process->pool, scoreboard_shm, 1); - if (rv || !(sb_shared = apr_shm_baseaddr_get(*scoreboard_shm))) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "Child %d: Unable to reopen the scoreboard from the parent", my_pid); - exit(APEXIT_CHILDINIT); - } - /* We must 'initialize' the scoreboard to relink all the - * process-local pointer arrays into the shared memory block. - */ - ap_init_scoreboard(sb_shared); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: Retrieved our scoreboard from the parent.", my_pid); -} - - -static int send_handles_to_child(apr_pool_t *p, - HANDLE child_ready_event, - HANDLE child_exit_event, - apr_proc_mutex_t *child_start_mutex, - apr_shm_t *scoreboard_shm, - HANDLE hProcess, - apr_file_t *child_in) -{ - apr_status_t rv; - HANDLE hCurrentProcess = GetCurrentProcess(); - HANDLE hDup; - HANDLE os_start; - HANDLE hScore; - DWORD BytesWritten; - - if (!DuplicateHandle(hCurrentProcess, child_ready_event, hProcess, &hDup, - EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the ready event handle for the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the exit event handle to the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, child_exit_event, hProcess, &hDup, - EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the exit event handle for the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the exit event handle to the child"); - return -1; - } - if ((rv = apr_os_proc_mutex_get(&os_start, child_start_mutex)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to retrieve the start mutex for the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, os_start, hProcess, &hDup, - SYNCHRONIZE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the start mutex to the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the start mutex to the child"); - return -1; - } - if ((rv = apr_os_shm_get(&hScore, scoreboard_shm)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to retrieve the scoreboard handle for the child"); - return -1; - } - if (!DuplicateHandle(hCurrentProcess, hScore, hProcess, &hDup, - FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Unable to duplicate the scoreboard handle to the child"); - return -1; - } - if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to send the scoreboard handle to the child"); - return -1; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Parent: Sent the scoreboard to the child"); - return 0; -} - - -/* - * get_listeners_from_parent() - * The listen sockets are opened in the parent. This function, which runs - * exclusively in the child process, receives them from the parent and - * makes them availeble in the child. - */ -void get_listeners_from_parent(server_rec *s) -{ - WSAPROTOCOL_INFO WSAProtocolInfo; - ap_listen_rec *lr; - DWORD BytesRead; - int lcnt = 0; - SOCKET nsd; - - /* Set up a default listener if necessary */ - if (ap_listeners == NULL) { - ap_listen_rec *lr; - lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); - lr->sd = NULL; - lr->next = ap_listeners; - ap_listeners = lr; - } - - /* Open the pipe to the parent process to receive the inherited socket - * data. The sockets have been set to listening in the parent process. - * - * *** We now do this was back in winnt_rewrite_args - * pipe = GetStdHandle(STD_INPUT_HANDLE); - */ - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { - if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), - &BytesRead, (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "setup_inherited_listeners: Unable to read socket data from parent"); - exit(APEXIT_CHILDINIT); - } - nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &WSAProtocolInfo, 0, 0); - if (nsd == INVALID_SOCKET) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, - "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); - exit(APEXIT_CHILDINIT); - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - HANDLE hProcess = GetCurrentProcess(); - HANDLE dup; - if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - closesocket(nsd); - nsd = (SOCKET) dup; - } - } - else { - /* A different approach. Many users report errors such as - * (32538)An operation was attempted on something that is not - * a socket. : Parent: WSADuplicateSocket failed... - * - * This appears that the duplicated handle is no longer recognized - * as a socket handle. SetHandleInformation should overcome that - * problem by not altering the handle identifier. But this won't - * work on 9x - it's unsupported. - */ - if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf, - "set_listeners_noninheritable: SetHandleInformation failed."); - } - } - apr_os_sock_put(&lr->sd, &nsd, s->process->pool); - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Child %d: retrieved %d listeners from parent", my_pid, lcnt); -} - - -static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId, - apr_file_t *child_in) -{ - apr_status_t rv; - int lcnt = 0; - ap_listen_rec *lr; - LPWSAPROTOCOL_INFO lpWSAProtocolInfo; - DWORD BytesWritten; - - /* Run the chain of open sockets. For each socket, duplicate it - * for the target process then send the WSAPROTOCOL_INFO - * (returned by dup socket) to the child. - */ - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { - int nsd; - lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO)); - apr_os_sock_get(&nsd,lr->sd); - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf, - "Parent: Duplicating socket %d and sending it to child process %d", - nsd, dwProcessId); - if (WSADuplicateSocket(nsd, dwProcessId, - lpWSAProtocolInfo) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf, - "Parent: WSADuplicateSocket failed for socket %d. Check the FAQ.", lr->sd ); - return -1; - } - - if ((rv = apr_file_write_full(child_in, lpWSAProtocolInfo, - sizeof(WSAPROTOCOL_INFO), &BytesWritten)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to write duplicated socket %d to the child.", lr->sd ); - return -1; - } - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, - "Parent: Sent %d listeners to child %d", lcnt, dwProcessId); - return 0; -} - -enum waitlist_e { - waitlist_ready = 0, - waitlist_term = 1 -}; - -static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_event, - DWORD *child_pid) -{ - /* These NEVER change for the lifetime of this parent - */ - static char **args = NULL; - static char pidbuf[28]; - - apr_status_t rv; - apr_pool_t *ptemp; - apr_procattr_t *attr; - apr_proc_t new_child; - apr_file_t *child_out, *child_err; - HANDLE hExitEvent; - HANDLE waitlist[2]; /* see waitlist_e */ - char *cmd; - char *cwd; - char **env; - int envc; - - apr_pool_sub_make(&ptemp, p, NULL); - - /* Build the command line. Should look something like this: - * C:/apache/bin/apache.exe -f ap_server_confname - * First, get the path to the executable... - */ - apr_procattr_create(&attr, ptemp); - apr_procattr_cmdtype_set(attr, APR_PROGRAM); - apr_procattr_detach_set(attr, 1); - if (((rv = apr_filepath_get(&cwd, 0, ptemp)) != APR_SUCCESS) - || ((rv = apr_procattr_dir_set(attr, cwd)) != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Failed to get the current path"); - } - - if (!args) { - /* Build the args array, only once since it won't change - * for the lifetime of this parent process. - */ - if ((rv = ap_os_proc_filepath(&cmd, ptemp)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, ap_server_conf, - "Parent: Failed to get full path of %s", - ap_server_conf->process->argv[0]); - apr_pool_destroy(ptemp); - return -1; - } - - args = malloc((ap_server_conf->process->argc + 1) * sizeof (char*)); - memcpy(args + 1, ap_server_conf->process->argv + 1, - (ap_server_conf->process->argc - 1) * sizeof (char*)); - args[0] = malloc(strlen(cmd) + 1); - strcpy(args[0], cmd); - args[ap_server_conf->process->argc] = NULL; - } - else { - cmd = args[0]; - } - - /* Create a pipe to send handles to the child */ - if ((rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, - APR_NO_PIPE, APR_NO_PIPE)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to create child stdin pipe."); - apr_pool_destroy(ptemp); - return -1; - } - - /* httpd-2.0/2.2 specific to work around apr_proc_create bugs */ - /* set "NUL" as sysout for the child */ - if (((rv = apr_file_open(&child_out, "NUL", APR_WRITE | APR_READ, APR_OS_DEFAULT,p)) - != APR_SUCCESS) || - ((rv = apr_procattr_child_out_set(attr, child_out, NULL)) - != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Parent: Could not set child process stdout"); - } - if (((rv = apr_file_open_stderr(&child_err, p)) - != APR_SUCCESS) || - ((rv = apr_procattr_child_err_set(attr, child_err, NULL)) - != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "Parent: Could not set child process stderr"); - } - - /* Create the child_ready_event */ - waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!waitlist[waitlist_ready]) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Could not create ready event for child process"); - apr_pool_destroy (ptemp); - return -1; - } - - /* Create the child_exit_event */ - hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!hExitEvent) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Could not create exit event for child process"); - apr_pool_destroy(ptemp); - CloseHandle(waitlist[waitlist_ready]); - return -1; - } - - /* Build the env array */ - for (envc = 0; _environ[envc]; ++envc) { - ; - } - env = apr_palloc(ptemp, (envc + 2) * sizeof (char*)); - memcpy(env, _environ, envc * sizeof (char*)); - apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%i", parent_pid); - env[envc] = pidbuf; - env[envc + 1] = NULL; - - rv = apr_proc_create(&new_child, cmd, args, env, attr, ptemp); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Failed to create the child process."); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(waitlist[waitlist_ready]); - CloseHandle(new_child.hproc); - return -1; - } - apr_file_close(child_out); - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Created child process %d", new_child.pid); - - if (send_handles_to_child(ptemp, waitlist[waitlist_ready], hExitEvent, - start_mutex, ap_scoreboard_shm, - new_child.hproc, new_child.in)) { - /* - * This error is fatal, mop up the child and move on - * We toggle the child's exit event to cause this child - * to quit even as it is attempting to start. - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(waitlist[waitlist_ready]); - CloseHandle(new_child.hproc); - return -1; - } - - /* Important: - * Give the child process a chance to run before dup'ing the sockets. - * We have already set the listening sockets noninheritable, but if - * WSADuplicateSocket runs before the child process initializes - * the listeners will be inherited anyway. - */ - waitlist[waitlist_term] = new_child.hproc; - rv = WaitForMultipleObjects(2, waitlist, FALSE, INFINITE); - CloseHandle(waitlist[waitlist_ready]); - if (rv != WAIT_OBJECT_0) { - /* - * Outch... that isn't a ready signal. It's dead, Jim! - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(new_child.hproc); - return -1; - } - - if (send_listeners_to_child(ptemp, new_child.pid, new_child.in)) { - /* - * This error is fatal, mop up the child and move on - * We toggle the child's exit event to cause this child - * to quit even as it is attempting to start. - */ - SetEvent(hExitEvent); - apr_pool_destroy(ptemp); - CloseHandle(hExitEvent); - CloseHandle(new_child.hproc); - return -1; - } - - apr_file_close(new_child.in); - - *child_exit_event = hExitEvent; - *child_proc = new_child.hproc; - *child_pid = new_child.pid; - - return 0; -} - -/*********************************************************************** - * master_main() - * master_main() runs in the parent process. It creates the child - * process which handles HTTP requests then waits on one of three - * events: - * - * restart_event - * ------------- - * The restart event causes master_main to start a new child process and - * tells the old child process to exit (by setting the child_exit_event). - * The restart event is set as a result of one of the following: - * 1. An apache -k restart command on the command line - * 2. A command received from Windows service manager which gets - * translated into an ap_signal_parent(SIGNAL_PARENT_RESTART) - * call by code in service.c. - * 3. The child process calling ap_signal_parent(SIGNAL_PARENT_RESTART) - * as a result of hitting MaxRequestsPerChild. - * - * shutdown_event - * -------------- - * The shutdown event causes master_main to tell the child process to - * exit and that the server is shutting down. The shutdown event is - * set as a result of one of the following: - * 1. An apache -k shutdown command on the command line - * 2. A command received from Windows service manager which gets - * translated into an ap_signal_parent(SIGNAL_PARENT_SHUTDOWN) - * call by code in service.c. - * - * child process handle - * -------------------- - * The child process handle will be signaled if the child process - * exits for any reason. In a normal running server, the signaling - * of this event means that the child process has exited prematurely - * due to a seg fault or other irrecoverable error. For server - * robustness, master_main will restart the child process under this - * condtion. - * - * master_main uses the child_exit_event to signal the child process - * to exit. - **********************************************************************/ -#define NUM_WAIT_HANDLES 3 -#define CHILD_HANDLE 0 -#define SHUTDOWN_HANDLE 1 -#define RESTART_HANDLE 2 -static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event) -{ - int rv, cld; - int restart_pending; - int shutdown_pending; - HANDLE child_exit_event; - HANDLE event_handles[NUM_WAIT_HANDLES]; - DWORD child_pid; - - restart_pending = shutdown_pending = 0; - - event_handles[SHUTDOWN_HANDLE] = shutdown_event; - event_handles[RESTART_HANDLE] = restart_event; - - /* Create a single child process */ - rv = create_process(pconf, &event_handles[CHILD_HANDLE], - &child_exit_event, &child_pid); - if (rv < 0) - { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "master_main: create child process failed. Exiting."); - shutdown_pending = 1; - goto die_now; - } - if (!strcasecmp(signal_arg, "runservice")) { - mpm_service_started(); - } - - /* Update the scoreboard. Note that there is only a single active - * child at once. - */ - ap_scoreboard_image->parent[0].quiescing = 0; - ap_scoreboard_image->parent[0].pid = child_pid; - - /* Wait for shutdown or restart events or for child death */ - winnt_mpm_state = AP_MPMQ_RUNNING; - rv = WaitForMultipleObjects(NUM_WAIT_HANDLES, (HANDLE *) event_handles, FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK,APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "master_main: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown"); - shutdown_pending = 1; - } - else if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); - shutdown_pending = 1; - } - else if (cld == SHUTDOWN_HANDLE) { - /* shutdown_event signalled */ - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, s, - "Parent: Received shutdown signal -- Shutting down the server."); - if (ResetEvent(shutdown_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "ResetEvent(shutdown_event)"); - } - } - else if (cld == RESTART_HANDLE) { - /* Received a restart event. Prepare the restart_event to be reused - * then signal the child process to exit. - */ - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, - "Parent: Received restart signal -- Restarting the server."); - if (ResetEvent(restart_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "Parent: ResetEvent(restart_event) failed."); - } - if (SetEvent(child_exit_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "Parent: SetEvent for child process %d failed.", - event_handles[CHILD_HANDLE]); - } - /* Don't wait to verify that the child process really exits, - * just move on with the restart. - */ - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - else { - /* The child process exited prematurely due to a fatal error. */ - DWORD exitcode; - if (!GetExitCodeProcess(event_handles[CHILD_HANDLE], &exitcode)) { - /* HUH? We did exit, didn't we? */ - exitcode = APEXIT_CHILDFATAL; - } - if ( exitcode == APEXIT_CHILDFATAL - || exitcode == APEXIT_CHILDINIT - || exitcode == APEXIT_INIT) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "Parent: child process exited with status %u -- Aborting.", exitcode); - } - else { - int i; - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: child process exited with status %u -- Restarting.", exitcode); - for (i = 0; i < ap_threads_per_child; i++) { - ap_update_child_status_from_indexes(0, i, SERVER_DEAD, NULL); - } - } - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - if (restart_pending) { - ++ap_my_generation; - ap_scoreboard_image->global->running_generation = ap_my_generation; - } -die_now: - if (shutdown_pending) - { - int timeout = 30000; /* Timeout is milliseconds */ - winnt_mpm_state = AP_MPMQ_STOPPING; - - /* This shutdown is only marginally graceful. We will give the - * child a bit of time to exit gracefully. If the time expires, - * the child will be wacked. - */ - if (!strcasecmp(signal_arg, "runservice")) { - mpm_service_stopping(); - } - /* Signal the child processes to exit */ - if (SetEvent(child_exit_event) == 0) { - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), ap_server_conf, - "Parent: SetEvent for child process %d failed", event_handles[CHILD_HANDLE]); - } - if (event_handles[CHILD_HANDLE]) { - rv = WaitForSingleObject(event_handles[CHILD_HANDLE], timeout); - if (rv == WAIT_OBJECT_0) { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Child process exited successfully."); - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - else { - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Parent: Forcing termination of child process %d ", event_handles[CHILD_HANDLE]); - TerminateProcess(event_handles[CHILD_HANDLE], 1); - CloseHandle(event_handles[CHILD_HANDLE]); - event_handles[CHILD_HANDLE] = NULL; - } - } - CloseHandle(child_exit_event); - return 0; /* Tell the caller we do not want to restart */ - } - winnt_mpm_state = AP_MPMQ_STARTING; - CloseHandle(child_exit_event); - return 1; /* Tell the caller we want a restart */ -} - -/* service_nt_main_fn needs to append the StartService() args - * outside of our call stack and thread as the service starts... - */ -apr_array_header_t *mpm_new_argv; - -/* Remember service_to_start failures to log and fail in pre_config. - * Remember inst_argc and inst_argv for installing or starting the - * service after we preflight the config. - */ - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMON_USED: - *result = MAXIMUM_WAIT_OBJECTS; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = thread_limit; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MIN_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_SPARE_THREADS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MAX_REQUESTS_DAEMON: - *result = ap_max_requests_per_child; - return APR_SUCCESS; - case AP_MPMQ_MAX_DAEMONS: - *result = 0; - return APR_SUCCESS; - case AP_MPMQ_MPM_STATE: - *result = winnt_mpm_state; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -#define SERVICE_UNSET (-1) -static apr_status_t service_set = SERVICE_UNSET; -static apr_status_t service_to_start_success; -static int inst_argc; -static const char * const *inst_argv; -static char *service_name = NULL; - -void winnt_rewrite_args(process_rec *process) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [transition for WinNT, nothing for Win9x] - * -k (!)install [error out if name is not installed] - * -k uninstall - * -k stop - * -k shutdown (same as -k stop). Maintained for backward compatability. - * - * We can't leave this phase until we know our identity - * and modify the command arguments appropriately. - * - * We do not care if the .conf file exists or is parsable when - * attempting to stop or uninstall a service. - */ - apr_status_t rv; - char *def_server_root; - char *binpath; - char optbuf[3]; - const char *optarg; - int fixed_args; - char *pid; - apr_getopt_t *opt; - int running_as_service = 1; - int errout = 0; - - pconf = process->pconf; - - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osver); - - /* AP_PARENT_PID is only valid in the child */ - pid = getenv("AP_PARENT_PID"); - if (pid) - { - HANDLE filehand; - HANDLE hproc = GetCurrentProcess(); - - /* This is the child */ - my_pid = GetCurrentProcessId(); - parent_pid = (DWORD) atol(pid); - - /* Prevent holding open the (nonexistant) console */ - real_exit_code = 0; - - /* The parent gave us stdin, we need to remember this - * handle, and no longer inherit it at our children - * (we can't slurp it up now, we just aren't ready yet). - * The original handle is closed below, at apr_file_dup2() - */ - pipe = GetStdHandle(STD_INPUT_HANDLE); - if (DuplicateHandle(hproc, pipe, - hproc, &filehand, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - pipe = filehand; - } - - /* The parent gave us stdout of the NUL device, - * and expects us to suck up stdin of all of our - * shared handles and data from the parent. - * Don't infect child processes with our stdin - * handle, use another handle to NUL! - */ - { - apr_file_t *infile, *outfile; - if ((apr_file_open_stdout(&outfile, process->pool) == APR_SUCCESS) - && (apr_file_open_stdin(&infile, process->pool) == APR_SUCCESS)) - apr_file_dup2(infile, outfile, process->pool); - } - - /* This child needs the existing stderr opened for logging, - * already - */ - - /* The parent is responsible for providing the - * COMPLETE ARGUMENTS REQUIRED to the child. - * - * No further argument parsing is needed, but - * for good measure we will provide a simple - * signal string for later testing. - */ - signal_arg = "runchild"; - return; - } - - /* This is the parent, we have a long way to go :-) */ - parent_pid = my_pid = GetCurrentProcessId(); - - /* This behavior is voided by setting real_exit_code to 0 */ - atexit(hold_console_open_on_error); - - /* Rewrite process->argv[]; - * - * strip out -k signal into signal_arg - * strip out -n servicename and set the names - * add default -d serverroot from the path of this executable - * - * The end result will look like: - * - * The invocation command (%0) - * The -d serverroot default from the running executable - * The requested service's (-n) registry ConfigArgs - * The WinNT SCM's StartService() args - */ - if ((rv = ap_os_proc_filepath(&binpath, process->pconf)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_CRIT, rv, NULL, - "Failed to get the full path of %s", process->argv[0]); - exit(APEXIT_INIT); - } - /* WARNING: There is an implict assumption here that the - * executable resides in ServerRoot or ServerRoot\bin - */ - def_server_root = (char *) apr_filename_of_pathname(binpath); - if (def_server_root > binpath) { - *(def_server_root - 1) = '\0'; - def_server_root = (char *) apr_filename_of_pathname(binpath); - if (!strcasecmp(def_server_root, "bin")) - *(def_server_root - 1) = '\0'; - } - apr_filepath_merge(&def_server_root, NULL, binpath, - APR_FILEPATH_TRUENAME, process->pool); - - /* Use process->pool so that the rewritten argv - * lasts for the lifetime of the server process, - * because pconf will be destroyed after the - * initial pre-flight of the config parser. - */ - mpm_new_argv = apr_array_make(process->pool, process->argc + 2, - sizeof(const char *)); - *(const char **)apr_array_push(mpm_new_argv) = process->argv[0]; - *(const char **)apr_array_push(mpm_new_argv) = "-d"; - *(const char **)apr_array_push(mpm_new_argv) = def_server_root; - - fixed_args = mpm_new_argv->nelts; - - optbuf[0] = '-'; - optbuf[2] = '\0'; - apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv); - opt->errfn = NULL; - while ((rv = apr_getopt(opt, "wn:k:" AP_SERVER_BASEARGS, - optbuf + 1, &optarg)) == APR_SUCCESS) { - switch (optbuf[1]) { - - /* Shortcuts; include the -w option to hold the window open on error. - * This must not be toggled once we reset real_exit_code to 0! - */ - case 'w': - if (real_exit_code) - real_exit_code = 2; - break; - - case 'n': - service_set = mpm_service_set_name(process->pool, &service_name, - optarg); - break; - - case 'k': - signal_arg = optarg; - break; - - case 'E': - errout = 1; - /* Fall through so the Apache main() handles the 'E' arg */ - default: - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, optbuf); - - if (optarg) { - *(const char **)apr_array_push(mpm_new_argv) = optarg; - } - break; - } - } - - /* back up to capture the bad argument */ - if (rv == APR_BADCH || rv == APR_BADARG) { - opt->ind--; - } - - while (opt->ind < opt->argc) { - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, opt->argv[opt->ind++]); - } - - /* Track the number of args actually entered by the user */ - inst_argc = mpm_new_argv->nelts - fixed_args; - - /* Provide a default 'run' -k arg to simplify signal_arg tests */ - if (!signal_arg) - { - signal_arg = "run"; - running_as_service = 0; - } - - if (!strcasecmp(signal_arg, "runservice")) - { - /* Start the NT Service _NOW_ because the WinNT SCM is - * expecting us to rapidly assume control of our own - * process, the SCM will tell us our service name, and - * may have extra StartService() command arguments to - * add for us. - * - * The SCM will generally invoke the executable with - * the c:\win\system32 default directory. This is very - * lethal if folks use ServerRoot /foopath on windows - * without a drive letter. Change to the default root - * (path to apache root, above /bin) for safety. - */ - apr_filepath_set(def_server_root, process->pool); - - /* Any other process has a console, so we don't to begin - * a Win9x service until the configuration is parsed and - * any command line errors are reported. - * - * We hold the return value so that we can die in pre_config - * after logging begins, and the failure can land in the log. - */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - apr_file_t *nullfile; - - if (!errout) { - mpm_nt_eventlog_stderr_open(service_name, process->pool); - } - service_to_start_success = mpm_service_to_start(&service_name, - process->pool); - if (service_to_start_success == APR_SUCCESS) { - service_set = APR_SUCCESS; - } - - /* Open a null handle to soak stdout in this process. - * Windows service processes are missing any file handle - * usable for stdin/out/err. This was the cause of later - * trouble with invocations of apr_file_open_stdout() - */ - if ((rv = apr_file_open(&nullfile, "NUL", - APR_READ | APR_WRITE, APR_OS_DEFAULT, - process->pool)) == APR_SUCCESS) { - apr_file_t *nullstdout; - if (apr_file_open_stdout(&nullstdout, process->pool) - == APR_SUCCESS) - apr_file_dup2(nullstdout, nullfile, process->pool); - apr_file_close(nullfile); - } - } - } - - /* Get the default for any -k option, except run */ - if (service_set == SERVICE_UNSET && strcasecmp(signal_arg, "run")) { - service_set = mpm_service_set_name(process->pool, &service_name, - AP_DEFAULT_SERVICE_NAME); - } - - if (!strcasecmp(signal_arg, "install")) /* -k install */ - { - if (service_set == APR_SUCCESS) - { - ap_log_error(APLOG_MARK,APLOG_ERR, 0, NULL, - "%s: Service is already installed.", service_name); - exit(APEXIT_INIT); - } - } - else if (running_as_service) - { - if (service_set == APR_SUCCESS) - { - /* Attempt to Uninstall, or stop, before - * we can read the arguments or .conf files - */ - if (!strcasecmp(signal_arg, "uninstall")) { - rv = mpm_service_uninstall(); - exit(rv); - } - - if ((!strcasecmp(signal_arg, "stop")) || - (!strcasecmp(signal_arg, "shutdown"))) { - mpm_signal_service(process->pool, 0); - exit(0); - } - - rv = mpm_merge_service_args(process->pool, mpm_new_argv, - fixed_args); - if (rv == APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_INFO, 0, NULL, - "Using ConfigArgs of the installed service " - "\"%s\".", service_name); - } - else { - ap_log_error(APLOG_MARK,APLOG_WARNING, rv, NULL, - "No installed ConfigArgs for the service " - "\"%s\", using Apache defaults.", service_name); - } - } - else - { - ap_log_error(APLOG_MARK,APLOG_ERR, service_set, NULL, - "No installed service named \"%s\".", service_name); - exit(APEXIT_INIT); - } - } - if (strcasecmp(signal_arg, "install") && service_set && service_set != SERVICE_UNSET) - { - ap_log_error(APLOG_MARK,APLOG_ERR, service_set, NULL, - "No installed service named \"%s\".", service_name); - exit(APEXIT_INIT); - } - - /* Track the args actually entered by the user. - * These will be used for the -k install parameters, as well as - * for the -k start service override arguments. - */ - inst_argv = (const char * const *)mpm_new_argv->elts - + mpm_new_argv->nelts - inst_argc; - - process->argc = mpm_new_argv->nelts; - process->argv = (const char * const *) mpm_new_argv->elts; -} - - -static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *ptemp) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [WinNT errors logged from rewrite_args] - */ - - /* Initialize shared static objects. - */ - pconf = pconf_; - - if (ap_exists_config_define("ONE_PROCESS") || - ap_exists_config_define("DEBUG")) - one_process = -1; - - if (!strcasecmp(signal_arg, "runservice") - && (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - && (service_to_start_success != APR_SUCCESS)) { - ap_log_error(APLOG_MARK,APLOG_CRIT, service_to_start_success, NULL, - "%s: Unable to start the service manager.", - service_name); - exit(APEXIT_INIT); - } - - /* Win9x: disable AcceptEx */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - use_acceptex = 0; - } - - ap_listen_pre_config(); - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; -#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#endif - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - return OK; -} - -static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* s) -{ - static int restart_num = 0; - apr_status_t rv = 0; - - /* Handle the following SCM aspects in this phase: - * - * -k install - * -k config - * -k start - * -k restart - * -k runservice [Win95, only once - after we parsed the config] - * - * because all of these signals are useful _only_ if there - * is a valid conf\httpd.conf environment to start. - * - * We reached this phase by avoiding errors that would cause - * these options to fail unexpectedly in another process. - */ - - if (!strcasecmp(signal_arg, "install")) { - rv = mpm_service_install(ptemp, inst_argc, inst_argv, 0); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - if (!strcasecmp(signal_arg, "config")) { - rv = mpm_service_install(ptemp, inst_argc, inst_argv, 1); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (!strcasecmp(signal_arg, "start")) { - ap_listen_rec *lr; - - /* Close the listening sockets. */ - for (lr = ap_listeners; lr; lr = lr->next) { - apr_socket_close(lr->sd); - lr->active = 0; - } - rv = mpm_service_start(ptemp, inst_argc, inst_argv); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (!strcasecmp(signal_arg, "restart")) { - mpm_signal_service(ptemp, 1); - apr_pool_destroy(s->process->pool); - apr_terminate(); - exit(rv); - } - - if (parent_pid == my_pid) - { - if (restart_num++ == 1) - { - /* This code should be run once in the parent and not run - * across a restart - */ - PSECURITY_ATTRIBUTES sa = GetNullACL(); /* returns NULL if invalid (Win95?) */ - setup_signal_names(apr_psprintf(pconf,"ap%d", parent_pid)); - - ap_log_pid(pconf, ap_pid_fname); - - /* Create shutdown event, apPID_shutdown, where PID is the parent - * Apache process ID. Shutdown is signaled by 'apache -k shutdown'. - */ - shutdown_event = CreateEvent(sa, FALSE, FALSE, signal_shutdown_name); - if (!shutdown_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Cannot create shutdown event %s", signal_shutdown_name); - CleanNullACL((void *)sa); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Create restart event, apPID_restart, where PID is the parent - * Apache process ID. Restart is signaled by 'apache -k restart'. - */ - restart_event = CreateEvent(sa, FALSE, FALSE, signal_restart_name); - if (!restart_event) { - CloseHandle(shutdown_event); - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, - "Parent: Cannot create restart event %s", signal_restart_name); - CleanNullACL((void *)sa); - return HTTP_INTERNAL_SERVER_ERROR; - } - CleanNullACL((void *)sa); - - /* Now that we are flying at 15000 feet... - * wipe out the Win95 service console, - * signal the SCM the WinNT service started, or - * if not a service, setup console handlers instead. - */ - if (!strcasecmp(signal_arg, "runservice")) - { - if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT) - { - rv = mpm_service_to_start(&service_name, - s->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s: Unable to start the service manager.", - service_name); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - } - - /* Create the start mutex, as an unnamed object for security. - * Ths start mutex is used during a restart to prevent more than - * one child process from entering the accept loop at once. - */ - rv = apr_proc_mutex_create(&start_mutex, NULL, - APR_LOCK_DEFAULT, - ap_server_conf->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s: Unable to create the start_mutex.", - service_name); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - /* Always reset our console handler to be the first, even on a restart - * because some modules (e.g. mod_perl) might have set a console - * handler to terminate the process. - */ - if (strcasecmp(signal_arg, "runservice")) - mpm_start_console_handler(); - } - else /* parent_pid != my_pid */ - { - mpm_start_child_console_handler(); - } - return OK; -} - -/* This really should be a post_config hook, but the error log is already - * redirected by that point, so we need to do this in the open_logs phase. - */ -static int winnt_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - /* Initialize shared static objects. - */ - ap_server_conf = s; - - if (parent_pid != my_pid) { - return OK; - } - - /* We cannot initialize our listeners if we are restarting - * (the parent process already has glomed on to them) - * nor should we do so for service reconfiguration - * (since the service may already be running.) - */ - if (!strcasecmp(signal_arg, "restart") - || !strcasecmp(signal_arg, "config")) { - return OK; - } - - if (ap_setup_listeners(s) < 1) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, - NULL, "no listening sockets available, shutting down"); - return DONE; - } - - return OK; -} - -static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s) -{ - apr_status_t rv; - - setup_signal_names(apr_psprintf(pchild,"ap%d", parent_pid)); - - /* This is a child process, not in single process mode */ - if (!one_process) { - /* Set up events and the scoreboard */ - get_handles_from_parent(s, &exit_event, &start_mutex, - &ap_scoreboard_shm); - - /* Set up the listeners */ - get_listeners_from_parent(s); - - /* Done reading from the parent, close that channel */ - CloseHandle(pipe); - - ap_my_generation = ap_scoreboard_image->global->running_generation; - } - else { - /* Single process mode - this lock doesn't even need to exist */ - rv = apr_proc_mutex_create(&start_mutex, signal_name_prefix, - APR_LOCK_DEFAULT, s->process->pool); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, - "%s child %d: Unable to init the start_mutex.", - service_name, my_pid); - exit(APEXIT_CHILDINIT); - } - - /* Borrow the shutdown_even as our _child_ loop exit event */ - exit_event = shutdown_event; - } -} - - -AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) -{ - static int restart = 0; /* Default is "not a restart" */ - - if (!restart) { - first_thread_limit = thread_limit; - } - - if (changed_limit_at_restart) { - ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf, - "WARNING: Attempt to change ThreadLimit ignored " - "during restart"); - changed_limit_at_restart = 0; - } - - /* ### If non-graceful restarts are ever introduced - we need to rerun - * the pre_mpm hook on subsequent non-graceful restarts. But Win32 - * has only graceful style restarts - and we need this hook to act - * the same on Win32 as on Unix. - */ - if (!restart && ((parent_pid == my_pid) || one_process)) { - /* Set up the scoreboard. */ - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { - return 1; - } - } - - if ((parent_pid != my_pid) || one_process) - { - /* The child process or in one_process (debug) mode - */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Child process is running", my_pid); - - child_main(pconf); - - ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Child process is exiting", my_pid); - return 1; - } - else - { - /* A real-honest to goodness parent */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - - restart = master_main(ap_server_conf, shutdown_event, restart_event); - - if (!restart) - { - /* Shutting down. Clean up... */ - const char *pidfile = ap_server_root_relative (pconf, ap_pid_fname); - - if (pidfile != NULL && unlink(pidfile) == 0) { - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, - ap_server_conf, "removed PID file %s (pid=%ld)", - pidfile, GetCurrentProcessId()); - } - apr_proc_mutex_destroy(start_mutex); - - CloseHandle(restart_event); - CloseHandle(shutdown_event); - - return 1; - } - } - - return 0; /* Restart */ -} - -static void winnt_hooks(apr_pool_t *p) -{ - /* The prefork open_logs phase must run before the core's, or stderr - * will be redirected to a file, and the messages won't print to the - * console. - */ - static const char *const aszSucc[] = {"core.c", NULL}; - - ap_hook_pre_config(winnt_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(winnt_post_config, NULL, NULL, 0); - ap_hook_child_init(winnt_child_init, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); -} - -AP_MODULE_DECLARE_DATA module mpm_winnt_module = { - MPM20_MODULE_STUFF, - winnt_rewrite_args, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - winnt_cmds, /* command apr_table_t */ - winnt_hooks /* register_hooks */ -}; - -#endif /* def WIN32 */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h b/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h deleted file mode 100644 index 8eb04303..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/mpm_winnt.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APACHE_MPM_WINNT_H -#define APACHE_MPM_WINNT_H - -#include "ap_listen.h" - -/* From service.c: */ - -#define SERVICE_APACHE_RESTART 128 - -#ifndef AP_DEFAULT_SERVICE_NAME -#define AP_DEFAULT_SERVICE_NAME "Apache2" -#endif - -#define SERVICECONFIG9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices" -#define SERVICECONFIG "System\\CurrentControlSet\\Services\\%s" -#define SERVICEPARAMS "System\\CurrentControlSet\\Services\\%s\\Parameters" - -apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, - const char *set_name); -apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, - int fixed_args); - -apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p); -apr_status_t mpm_service_started(void); -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - char const* const* argv, int reconfig); -apr_status_t mpm_service_uninstall(void); - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - char const* const* argv); - -void mpm_signal_service(apr_pool_t *ptemp, int signal); - -void mpm_service_stopping(void); - -void mpm_start_console_handler(void); -void mpm_start_child_console_handler(void); - -/* From nt_eventlog.c: */ - -void mpm_nt_eventlog_stderr_open(char *display_name, apr_pool_t *p); -void mpm_nt_eventlog_stderr_flush(void); - -/* From winnt.c: */ -extern int use_acceptex; -extern int winnt_mpm_state; -extern OSVERSIONINFO osver; -extern void clean_child_exit(int); - -void setup_signal_names(char *prefix); - -typedef enum { - SIGNAL_PARENT_SHUTDOWN, - SIGNAL_PARENT_RESTART, - SIGNAL_PARENT_RESTART_GRACEFUL -} ap_signal_parent_e; -AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type); - -/* - * The Windoes MPM uses a queue of completion contexts that it passes - * between the accept threads and the worker threads. Declare the - * functions to access the queue and the structures passed on the - * queue in the header file to enable modules to access them - * if necessary. The queue resides in the MPM. - */ -#ifdef CONTAINING_RECORD -#undef CONTAINING_RECORD -#endif -#define CONTAINING_RECORD(address, type, field) ((type *)( \ - (PCHAR)(address) - \ - (PCHAR)(&((type *)0)->field))) -#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 -typedef struct CompContext { - struct CompContext *next; - OVERLAPPED Overlapped; - apr_socket_t *sock; - SOCKET accept_socket; - char buff[2*PADDED_ADDR_SIZE]; - struct sockaddr *sa_server; - int sa_server_len; - struct sockaddr *sa_client; - int sa_client_len; - apr_pool_t *ptrans; - apr_bucket_alloc_t *ba; -} COMP_CONTEXT, *PCOMP_CONTEXT; - -typedef enum { - IOCP_CONNECTION_ACCEPTED = 1, - IOCP_WAIT_FOR_RECEIVE = 2, - IOCP_WAIT_FOR_TRANSMITFILE = 3, - IOCP_SHUTDOWN = 4 -} io_state_e; - -AP_DECLARE(PCOMP_CONTEXT) mpm_get_completion_context(void); -AP_DECLARE(void) mpm_recycle_completion_context(PCOMP_CONTEXT pCompContext); -AP_DECLARE(apr_status_t) mpm_post_completion_context(PCOMP_CONTEXT pCompContext, io_state_e state); -void hold_console_open_on_error(void); -#endif /* APACHE_MPM_WINNT_H */ diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c deleted file mode 100644 index 37a349e8..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/nt_eventlog.c +++ /dev/null @@ -1,175 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define CORE_PRIVATE - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_portable.h" -#include "ap_regkey.h" - -static char *display_name = NULL; -static HANDLE stderr_thread = NULL; -static HANDLE stderr_ready; - -static DWORD WINAPI service_stderr_thread(LPVOID hPipe) -{ - HANDLE hPipeRead = (HANDLE) hPipe; - HANDLE hEventSource; - char errbuf[256]; - char *errmsg = errbuf; - const char *errarg[9]; - DWORD errres; - ap_regkey_t *regkey; - apr_status_t rv; - apr_pool_t *p; - - apr_pool_sub_make(&p, NULL, NULL); - - errarg[0] = "The Apache service named"; - errarg[1] = display_name; - errarg[2] = "reported the following error:\r\n>>>"; - errarg[3] = errbuf; - errarg[4] = NULL; - errarg[5] = NULL; - errarg[6] = NULL; - errarg[7] = NULL; - errarg[8] = NULL; - - /* What are we going to do in here, bail on the user? not. */ - if ((rv = ap_regkey_open(®key, AP_REGKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Services\\" - "EventLog\\Application\\Apache Service", - APR_READ | APR_WRITE | APR_CREATE, p)) - == APR_SUCCESS) - { - DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | - EVENTLOG_INFORMATION_TYPE; - - /* The stock message file */ - ap_regkey_value_set(regkey, "EventMessageFile", - "%SystemRoot%\\System32\\netmsg.dll", - AP_REGKEY_EXPAND, p); - - ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData, - sizeof(dwData), REG_DWORD, p); - ap_regkey_close(regkey); - } - - hEventSource = RegisterEventSourceW(NULL, L"Apache Service"); - - SetEvent(stderr_ready); - - while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) - { - if ((errmsg > errbuf) || !apr_isspace(*errmsg)) - { - ++errmsg; - if ((*(errmsg - 1) == '\n') - || (errmsg >= errbuf + sizeof(errbuf) - 1)) - { - while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) { - --errmsg; - } - *errmsg = '\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; - } - } - } - - if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) { - apr_snprintf(errbuf, sizeof(errbuf), - "Win32 error %d reading stderr pipe stream\r\n", - GetLastError()); - - ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, - 3299, NULL, 9, 0, errarg, NULL); - } - - CloseHandle(hPipeRead); - DeregisterEventSource(hEventSource); - CloseHandle(stderr_thread); - stderr_thread = NULL; - apr_pool_destroy(p); - return 0; -} - - -void mpm_nt_eventlog_stderr_flush(void) -{ - HANDLE cleanup_thread = stderr_thread; - - if (cleanup_thread) { - HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE); - fclose(stderr); - CloseHandle(hErr); - WaitForSingleObject(cleanup_thread, 30000); - CloseHandle(cleanup_thread); - } -} - - -void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p) -{ - SECURITY_ATTRIBUTES sa; - HANDLE hProc = GetCurrentProcess(); - HANDLE hPipeRead = NULL; - HANDLE hPipeWrite = NULL; - HANDLE hDup = NULL; - DWORD threadid; - apr_file_t *eventlog_file; - apr_file_t *stderr_file; - - display_name = argv0; - - /* Create a pipe to send stderr messages to the system error log. - * - * _dup2() duplicates the write handle inheritable for us. - */ - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = FALSE; - CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0); - ap_assert(hPipeRead && hPipeWrite); - - stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL); - stderr_thread = CreateThread(NULL, 0, service_stderr_thread, - (LPVOID) hPipeRead, 0, &threadid); - ap_assert(stderr_ready && stderr_thread); - - WaitForSingleObject(stderr_ready, INFINITE); - - if ((apr_file_open_stderr(&stderr_file, p) - == APR_SUCCESS) - && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p) - == APR_SUCCESS)) - apr_file_dup2(stderr_file, eventlog_file, p); - - /* The code above _will_ corrupt the StdHandle... - * and we must do so anyways. We set this up only - * after we initialized the posix stderr API. - */ - ap_open_stderr_log(p); -} diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c deleted file mode 100644 index 8739dc08..00000000 --- a/rubbos/app/httpd-2.0.64/server/mpm/winnt/service.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This module ALONE requires the window message API from user.h - * and the default APR include of windows.h will omit it, so - * preload the API symbols now... - */ - -#define CORE_PRIVATE -#define _WINUSER_ - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "ap_regkey.h" - -#ifdef NOUSER -#undef NOUSER -#endif -#undef _WINUSER_ -#include <winuser.h> - -static char *mpm_service_name = NULL; -static char *mpm_display_name = NULL; - -static struct -{ - HANDLE mpm_thread; /* primary thread handle of the apache server */ - HANDLE service_thread; /* thread service/monitor handle */ - DWORD service_thread_id;/* thread service/monitor ID */ - HANDLE service_init; /* controller thread init mutex */ - HANDLE service_term; /* NT service thread kill signal */ - SERVICE_STATUS ssStatus; - SERVICE_STATUS_HANDLE hServiceStatus; -} globdat; - -static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint); - - -#define PRODREGKEY "SOFTWARE\\" AP_SERVER_BASEVENDOR "\\" \ - AP_SERVER_BASEPRODUCT "\\" AP_SERVER_BASEREVISION - -/* - * Get the server root from the registry into 'dir' which is - * size bytes long. Returns 0 if the server root was found - * or if the serverroot key does not exist (in which case - * dir will contain an empty string), or -1 if there was - * an error getting the key. - */ -apr_status_t ap_registry_get_server_root(apr_pool_t *p, char **buf) -{ - apr_status_t rv; - ap_regkey_t *key; - - if ((rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, PRODREGKEY, - APR_READ, p)) == APR_SUCCESS) { - rv = ap_regkey_value_get(buf, key, "ServerRoot", p); - ap_regkey_close(key); - if (rv == APR_SUCCESS) - return rv; - } - - if ((rv = ap_regkey_open(&key, AP_REGKEY_CURRENT_USER, PRODREGKEY, - APR_READ, p)) == APR_SUCCESS) { - rv = ap_regkey_value_get(buf, key, "ServerRoot", p); - ap_regkey_close(key); - if (rv == APR_SUCCESS) - return rv; - } - - *buf = NULL; - return rv; -} - - -/* The service configuration's is stored under the following trees: - * - * HKLM\System\CurrentControlSet\Services\[service name] - * - * \DisplayName - * \ImagePath - * \Parameters\ConfigArgs - * - * For Win9x, the launch service command is stored under: - * - * HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices\[service name] - */ - - -/* exit() for Win32 is macro mapped (horrible, we agree) that allows us - * to catch the non-zero conditions and inform the console process that - * the application died, and hang on to the console a bit longer. - * - * The macro only maps for http_main.c and other sources that include - * the service.h header, so we best assume it's an error to exit from - * _any_ other module. - * - * If real_exit_code is reset to 0, it will not be set or trigger this - * behavior on exit. All service and child processes are expected to - * reset this flag to zero to avoid undesireable side effects. - */ -AP_DECLARE_DATA int real_exit_code = 1; - -void hold_console_open_on_error(void) -{ - HANDLE hConIn; - HANDLE hConErr; - DWORD result; - time_t start; - time_t remains; - char *msg = "Note the errors or messages above, " - "and press the <ESC> key to exit. "; - CONSOLE_SCREEN_BUFFER_INFO coninfo; - INPUT_RECORD in; - char count[16]; - - if (!real_exit_code) - return; - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConErr = GetStdHandle(STD_ERROR_HANDLE); - if ((hConIn == INVALID_HANDLE_VALUE) || (hConErr == INVALID_HANDLE_VALUE)) - return; - if (!WriteConsole(hConErr, msg, strlen(msg), &result, NULL) || !result) - return; - if (!GetConsoleScreenBufferInfo(hConErr, &coninfo)) - return; - if (!SetConsoleMode(hConIn, ENABLE_MOUSE_INPUT | 0x80)) - return; - - start = time(NULL); - do - { - while (PeekConsoleInput(hConIn, &in, 1, &result) && result) - { - if (!ReadConsoleInput(hConIn, &in, 1, &result) || !result) - return; - if ((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown - && (in.Event.KeyEvent.uChar.AsciiChar == 27)) - return; - if (in.EventType == MOUSE_EVENT - && (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) - return; - } - remains = ((start + 30) - time(NULL)); - sprintf (count, "%d...", remains); - if (!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition)) - return; - if (!WriteConsole(hConErr, count, strlen(count), &result, NULL) - || !result) - return; - } - while ((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED); -} - -static BOOL die_on_logoff = FALSE; - -static LRESULT CALLBACK monitor_service_9x_proc(HWND hWnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ -/* 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) - && (die_on_logoff || (lParam != ENDSESSION_LOGOFF))) - { - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - if (wParam) - /* Don't leave this message until we are dead! */ - WaitForSingleObject(globdat.mpm_thread, 30000); - return 0; - } - return (DefWindowProc(hWnd, msg, wParam, lParam)); -} - -static DWORD WINAPI monitor_service_9x_thread(void *service_name) -{ - /* When running as a service under Windows 9x, there is no console - * window present, and no ConsoleCtrlHandler to call when the system - * is shutdown. If the WatchWindow thread is created with a NULL - * service_name argument, then the ...SystemMonitor window class is - * used to create the "Apache" window to watch for logoff and shutdown. - * If the service_name is provided, the ...ServiceMonitor window class - * is used to create the window named by the service_name argument, - * and the logoff message is ignored. - */ - WNDCLASS wc; - HWND hwndMain; - MSG msg; - - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = monitor_service_9x_proc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (service_name) - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - else - wc.lpszClassName = "ApacheWin95SystemMonitor"; - - die_on_logoff = service_name ? FALSE : TRUE; - - if (!RegisterClass(&wc)) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not register window class for WatchWindow"); - globdat.service_thread_id = 0; - return 0; - } - - /* Create an invisible window */ - hwndMain = CreateWindow(wc.lpszClassName, - service_name ? (char *) service_name : "Apache", - WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, NULL, NULL, NULL, NULL); - - if (!hwndMain) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not create WatchWindow"); - globdat.service_thread_id = 0; - return 0; - } - - /* 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(globdat.service_init); - - while (GetMessage(&msg, NULL, 0, 0)) - { - if (msg.message == WM_CLOSE) - DestroyWindow(hwndMain); - else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - globdat.service_thread_id = 0; - return 0; -} - - -static BOOL CALLBACK console_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_BREAK_EVENT: - fprintf(stderr, "Apache server restarting...\n"); - ap_signal_parent(SIGNAL_PARENT_RESTART); - return TRUE; - case CTRL_C_EVENT: - fprintf(stderr, "Apache server interrupted...\n"); - /* for Interrupt signals, shut down the server. - * Tell the system we have dealt with the signal - * without waiting for Apache to terminate. - */ - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Terminate signals, shut down the server. - * Wait for Apache to terminate, but respond - * after a reasonable time to tell the system - * that we did attempt to shut ourself down. - * THESE EVENTS WILL NOT OCCUR UNDER WIN9x! - */ - fprintf(stderr, "Apache server shutdown initiated...\n"); - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - Sleep(30000); - return TRUE; - } - - /* We should never get here, but this is (mostly) harmless */ - return FALSE; -} - - -static void stop_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, FALSE); -} - - -void mpm_start_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, TRUE); - atexit(stop_console_handler); -} - - -/* Special situation - children of services need to mind their - * P's & Q's and wait quietly, ignoring the mean OS signaling - * shutdown and other horrors, to kill them gracefully... - */ - -static BOOL CALLBACK child_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - /* for Interrupt signals, ignore them. - * The system will also signal the parent process, - * which will terminate Apache. - */ - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Shutdown signals, ignore them, but... . - * 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; -} - - -void service_stopped(void) -{ - /* Still have a thread & window to clean up, so signal now */ - if (globdat.service_thread) - { - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - /* Stop logging to the event log */ - mpm_nt_eventlog_stderr_flush(); - - /* Cause the service_nt_main_fn to complete */ - ReleaseMutex(globdat.service_term); - - ReportStatusToSCMgr(SERVICE_STOPPED, // service state - NO_ERROR, // exit code - 0); // wait hint - } - 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(const char **display_name, apr_pool_t *p) -{ - HANDLE hProc = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - HANDLE waitfor[2]; - - /* Prevent holding open the (hidden) console */ - real_exit_code = 0; - - /* GetCurrentThread returns a psuedo-handle, we need - * a real handle for another thread to wait upon. - */ - if (!DuplicateHandle(hProc, hThread, hProc, &(globdat.mpm_thread), - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - return APR_ENOTHREAD; - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - globdat.service_init = CreateEvent(NULL, FALSE, FALSE, NULL); - globdat.service_term = CreateMutex(NULL, TRUE, NULL); - if (!globdat.service_init || !globdat.service_term) { - return APR_EGENERAL; - } - - 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.service_init = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!globdat.service_init) { - return APR_EGENERAL; - } - - globdat.service_thread = CreateThread(NULL, 0, monitor_service_9x_thread, - (LPVOID) mpm_service_name, 0, - &globdat.service_thread_id); - } - - if (!globdat.service_thread) { - return APR_ENOTHREAD; - } - - waitfor[0] = globdat.service_init; - waitfor[1] = globdat.service_thread; - - /* Wait for controlling thread init or termination */ - if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) { - return APR_ENOTHREAD; - } - - atexit(service_stopped); - *display_name = mpm_display_name; - return APR_SUCCESS; -} - - -apr_status_t mpm_service_started(void) -{ - set_service_description(); - 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 - 30000); // wait hint -} - - -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - const char * const * argv, int reconfig) -{ - char key_name[MAX_PATH]; - char exe_path[MAX_PATH]; - char *launch_cmd; - ap_regkey_t *key; - apr_status_t rv; - - fprintf(stderr,reconfig ? "Reconfiguring the %s service\n" - : "Installing the %s service\n", mpm_display_name); - - /* ###: utf-ize */ - 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; - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CREATE_SERVICE); - 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); - - if (reconfig) { - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_CHANGE_CONFIG); - if (!schService) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR, - apr_get_os_error(), NULL, - "OpenService failed"); - } - /* ###: utf-ize */ - else if (!ChangeServiceConfig(schService, - SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, - launch_cmd, NULL, NULL, - "Tcpip\0Afd\0", NULL, NULL, - mpm_display_name)) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR, - apr_get_os_error(), NULL, - "ChangeServiceConfig failed"); - /* !schService aborts configuration below */ - CloseServiceHandle(schService); - schService = NULL; - } - } - else { - /* 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. - */ - /* ###: utf-ize */ - schService = CreateService(schSCManager, // SCManager database - mpm_service_name, // name of service - mpm_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 - NULL, // use SYSTEM account - NULL); // no password - - if (!schService) - { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to create WinNT Service Profile"); - CloseServiceHandle(schSCManager); - return (rv); - } - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - /* Store the launch command in the registry */ - launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, SERVICECONFIG9X, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_set(key, mpm_service_name, - launch_cmd, 0, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to add the RunServices registry entry.", - mpm_display_name); - return (rv); - } - - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to create the registry service key.", - mpm_display_name); - return (rv); - } - rv = ap_regkey_value_set(key, "ImagePath", launch_cmd, 0, pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store ImagePath in the registry.", - mpm_display_name); - ap_regkey_close(key); - return (rv); - } - rv = ap_regkey_value_set(key, "DisplayName", - mpm_display_name, 0, pconf); - ap_regkey_close(key); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store DisplayName in the registry.", - mpm_display_name); - return (rv); - } - } - - set_service_description(); - - /* For both WinNT & Win9x store the service ConfigArgs in the registry... - */ - apr_snprintf(key_name, sizeof(key_name), SERVICEPARAMS, mpm_service_name); - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_array_set(key, "ConfigArgs", argc, argv, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store the ConfigArgs in the registry.", - mpm_display_name); - return (rv); - } - fprintf(stderr,"The %s service is successfully installed.\n", mpm_display_name); - return APR_SUCCESS; -} - - -apr_status_t mpm_service_uninstall(void) -{ - char key_name[MAX_PATH]; - apr_status_t rv; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - fprintf(stderr,"Removing the %s service\n", mpm_display_name); - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CONNECT); - 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); - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, DELETE); - - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: OpenService failed", mpm_display_name); - return (rv); - } - - /* assure the service is stopped before continuing - * - * This may be out of order... we might not be able to be - * granted all access if the service is running anyway. - * - * And do we want to make it *this easy* for them - * to uninstall their service unintentionally? - */ - // ap_stop_service(schService); - - if (DeleteService(schService) == 0) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to delete the service.", mpm_display_name); - return (rv); - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - apr_status_t rv2, rv3; - ap_regkey_t *key; - fprintf(stderr,"Removing the %s service\n", mpm_display_name); - - /* TODO: assure the service is stopped before continuing */ - - rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, SERVICECONFIG9X, - APR_READ | APR_WRITE | APR_CREATE, pconf); - if (rv == APR_SUCCESS) { - rv = ap_regkey_value_remove(key, mpm_service_name, pconf); - ap_regkey_close(key); - } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to remove the RunServices registry " - "entry.", mpm_display_name); - } - - /* we blast Services/us, not just the Services/us/Parameters branch */ - apr_snprintf(key_name, sizeof(key_name), SERVICEPARAMS, mpm_service_name); - rv2 = ap_regkey_remove(AP_REGKEY_LOCAL_MACHINE, key_name, pconf); - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv3 = ap_regkey_remove(AP_REGKEY_LOCAL_MACHINE, key_name, pconf); - rv2 = (rv2 != APR_SUCCESS) ? rv2 : rv3; - if (rv2 != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv2, NULL, - "%s: Failed to remove the service config from the " - "registry.", mpm_display_name); - } - rv = (rv != APR_SUCCESS) ? rv : rv2; - if (rv != APR_SUCCESS) - return rv; - } - fprintf(stderr,"The %s service has been removed successfully.\n", mpm_display_name); - return APR_SUCCESS; -} - - -/* signal_service_transition is a simple thunk to signal the service - * and monitor its successful transition. If the signal passed is 0, - * then the caller is assumed to already have performed some service - * operation to be monitored (such as StartService), and no actual - * ControlService signal is sent. - */ - -static int signal_service_transition(SC_HANDLE schService, DWORD signal, DWORD pending, DWORD complete) -{ - if (signal && !ControlService(schService, signal, &globdat.ssStatus)) - return FALSE; - - do { - Sleep(1000); - if (!QueryServiceStatus(schService, &globdat.ssStatus)) - return FALSE; - } while (globdat.ssStatus.dwCurrentState == pending); - - return (globdat.ssStatus.dwCurrentState == complete); -} - - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - const char * const * argv) -{ - apr_status_t rv; - - fprintf(stderr,"Starting the %s service\n", mpm_display_name); - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - char **start_argv; - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_CONNECT); - 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); - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_START | SERVICE_QUERY_STATUS); - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to open the service.", mpm_display_name); - CloseServiceHandle(schSCManager); - return (rv); - } - - if (QueryServiceStatus(schService, &globdat.ssStatus) - && (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return 0; - } - - start_argv = malloc((argc + 1) * sizeof(const char **)); - memcpy(start_argv, argv, argc * sizeof(const char **)); - start_argv[argc] = NULL; - - rv = APR_EINIT; - /* ###: utf-ize */ - if (StartService(schService, argc, start_argv) - && signal_service_transition(schService, 0, /* test only */ - SERVICE_START_PENDING, - SERVICE_RUNNING)) - rv = APR_SUCCESS; - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - STARTUPINFO si; /* Filled in prior to call to CreateProcess */ - PROCESS_INFORMATION pi; /* filled in on call to CreateProcess */ - char exe_path[MAX_PATH]; - char exe_cmd[MAX_PATH * 4]; - char *next_arg; - int i; - - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - return 0; - } - - /* This may not appear intuitive, but Win9x will not allow a process - * to detach from the console without releasing the entire console. - * Ergo, we must spawn a new process for the service to get back our - * console window. - * The config is pre-flighted, so there should be no danger of failure. - */ - - 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; - } - - apr_snprintf(exe_cmd, sizeof(exe_cmd), - "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - next_arg = strchr(exe_cmd, '\0'); - for (i = 0; i < argc; ++i) { - apr_snprintf(next_arg, sizeof(exe_cmd) - (next_arg - exe_cmd), - " \"%s\"", argv[i]); - next_arg = strchr(exe_cmd, '\0'); - } - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; /* This might be redundant */ - - rv = APR_EINIT; - if (CreateProcess(NULL, exe_cmd, NULL, NULL, FALSE, - DETACHED_PROCESS, /* Creation flags */ - NULL, NULL, &si, &pi)) - { - DWORD code; - while (GetExitCodeProcess(pi.hProcess, &code) == STILL_ACTIVE) { - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - rv = APR_SUCCESS; - break; - } - Sleep (1000); - } - } - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - if (rv == APR_SUCCESS) - fprintf(stderr,"The %s service is running.\n", mpm_display_name); - else - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "%s: Failed to start the service process.", - mpm_display_name); - - return rv; -} - - -/* signal is zero to stop, non-zero for restart */ - -void mpm_signal_service(apr_pool_t *ptemp, int signal) -{ - int success = FALSE; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, // default machine & database - SC_MANAGER_CONNECT); - - if (!schSCManager) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the NT Service Manager"); - return; - } - - /* ###: utf-ize */ - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_INTERROGATE | SERVICE_QUERY_STATUS | - SERVICE_USER_DEFINED_CONTROL | - SERVICE_START | SERVICE_STOP); - - if (schService == NULL) { - /* Could not open the service */ - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the %s Service", mpm_display_name); - CloseServiceHandle(schSCManager); - return; - } - - if (!QueryServiceStatus(schService, &globdat.ssStatus)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Query of Service %s failed", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - if (!signal && (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)) { - fprintf(stderr,"The %s service is not started.\n", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - fprintf(stderr,"The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - if (!signal) - success = signal_service_transition(schService, - SERVICE_CONTROL_STOP, - SERVICE_STOP_PENDING, - SERVICE_STOPPED); - else if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - else - success = signal_service_transition(schService, - SERVICE_APACHE_RESTART, - SERVICE_START_PENDING, - SERVICE_RUNNING); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* !isWindowsNT() */ - { - DWORD service_pid; - HANDLE hwnd; - char prefix[20]; - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - hwnd = FindWindow("ApacheWin95ServiceMonitor", mpm_service_name); - if (hwnd && GetWindowThreadProcessId(hwnd, &service_pid)) - globdat.ssStatus.dwCurrentState = SERVICE_RUNNING; - else - { - globdat.ssStatus.dwCurrentState = SERVICE_STOPPED; - if (!signal) { - fprintf(stderr,"The %s service is not started.\n", mpm_display_name); - return; - } - } - - fprintf(stderr,"The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - apr_snprintf(prefix, sizeof(prefix), "ap%ld", (long)service_pid); - setup_signal_names(prefix); - - if (!signal) - { - int ticks = 60; - ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); - while (--ticks) - { - if (!IsWindow(hwnd)) { - success = TRUE; - break; - } - Sleep(1000); - } - } - else /* !stop */ - { - /* TODO: Aught to add a little test to the restart logic, and - * store the restart counter in the window's user dword. - * Then we can hang on and report a successful restart. But - * that's a project for another day. - */ - if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - return; - } - else { - success = TRUE; - ap_signal_parent(SIGNAL_PARENT_RESTART); - } - } - } - - if (success) - fprintf(stderr,"The %s service has %s.\n", mpm_display_name, - signal ? "restarted" : "stopped"); - else - fprintf(stderr,"Failed to %s the %s service.\n", - signal ? "restart" : "stop", mpm_display_name); -} |