You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@locus.apache.org on 2000/05/19 07:01:55 UTC

cvs commit: apache-2.0/src/modules/mpm/winnt winnt.c winnt.h

wrowe       00/05/18 22:01:54

  Modified:    src/os/win32 main_win32.c registry.c service.c service.h
               src/include ap_listen.h http_main.h
               src/lib/apr/include apr.hw
               src/lib/apr/threadproc/win32 proc.c
               src/modules/mpm/winnt winnt.c winnt.h
  Added:       src/os/win32 main_win32.h
  Log:
  
    Fixes to allow Apache to run as a Win95 service... highlights
  
    main_win32.h : Moved delarations to a header, by request
    ap_listen.h :  References types declared in http_config.h
    http_main.h :  Add the Win32 flavor entry point declaration
    apr.hw :       Cleanup the redundancy department of redundancy 
    win32/proc.c : Double null termination was required here
    
    Everything else should be obvious and isolated to Win32.
    Build files will be committed seperately.
  
  
  Revision  Changes    Path
  1.16      +89 -24    apache-2.0/src/os/win32/main_win32.c
  
  Index: main_win32.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/os/win32/main_win32.c,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- main_win32.c	2000/05/17 00:35:20	1.15
  +++ main_win32.c	2000/05/19 05:01:49	1.16
  @@ -65,7 +65,12 @@
    * link an executable without at least one object file. This
    * satistifies that requirement.
    */
  +
  +#ifdef WIN32
  +
   #define CORE_PRIVATE
  +
  +#include "main_win32.h"
   #include "httpd.h"
   #include "http_main.h"
   #include "http_config.h"
  @@ -74,12 +79,11 @@
   #include "http_log.h"
   #include "registry.h"
   #include "ap_config.h"
  +#include "..\..\modules\mpm\winnt\winnt.h"
   
  -API_EXPORT(int) apache_main(int argc, char *argv[]);
  -#define DEFAULTSERVICENAME "Apache"
  +static OSVERSIONINFO osver;
   
  -typedef void (CALLBACK *ap_completion_t)();
  -API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
  +#define DEFAULTSERVICENAME "Apache"
   
   static const char* read_config_cmd(char *filename, char *cmd, ap_pool_t *p)
   {
  @@ -110,6 +114,7 @@
       }
       return s;
   }
  +
   static void signal_parent(const char* file, const char* signal, 
                             ap_pool_t *p) 
   {
  @@ -199,12 +204,60 @@
       return FALSE;
   }
   
  +static BOOL CALLBACK child_control_handler(DWORD ctrl_type)
  +{
  +    switch (ctrl_type)
  +    {
  +        case CTRL_C_EVENT:
  +        case CTRL_BREAK_EVENT:
  +            fprintf(stderr, "Apache server interrupted...\n");
  +            /* 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;
  +}
  +
   void CALLBACK console_started_hook()
   {
  -    SetConsoleCtrlHandler(console_control_handler, TRUE);
  +    if (getenv("AP_PARENT_PID"))        
  +        SetConsoleCtrlHandler(child_control_handler, TRUE);
  +    else
  +        SetConsoleCtrlHandler(console_control_handler, TRUE);
  +}
   
  -    /* We do this only once, ever! */
  -    ap_mpm_init_complete = NULL;
  +void cwd_truepath()
  +{
  +    /* change to the drive with the executable */
  +    char buf[MAX_PATH], *term;
  +    GetModuleFileName(NULL, buf, MAX_PATH);
  +    term = strrchr(buf, '\\');
  +    if (!term)
  +	term = strrchr(buf, '/');
  +    if (!term)
  +	term = strrchr(buf, ':');
  +    if (term) {
  +	*term = '\0';
  +	chdir(buf);
  +	if (buf[1] == ':') {
  +	    buf[2] = 0;
  +	    chdir(buf);
  +	}
  +    }
   }
   
   int main(int argc, char *argv[])
  @@ -212,22 +265,23 @@
       ap_pool_t *pwincmd;
       int c, rv;
       char *ch;
  -    char *service_name = NULL; //DEFAULTSERVICENAME;
  +    char *service_name = NULL;
       char *signal = NULL;
       char *server_root = NULL;
       char *server_confname = SERVER_CONFIG_FILE;
       char *temp_server_confname = NULL;
       char cwd[MAX_STRING_LEN];
       char **new;
  -
  -    BOOLEAN install = FALSE;
  -    BOOLEAN uninstall = FALSE;
  -
  +    BOOL install = FALSE;
  +    BOOL uninstall = FALSE;
       ap_status_t status;
       ap_array_header_t *cmdtbl;
       int new_argc = 0;
   
  +    cwd_truepath();
  +
       status = ap_initialize();
  +
       if (status != APR_SUCCESS) {
           ap_log_error(APLOG_MARK, APLOG_ERR, status, NULL, 
                        "ap_initialize() failure");        
  @@ -241,6 +295,9 @@
           cleanup_and_exit();
       }
   
  +    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  +    GetVersionEx(&osver);
  +
       /* Set up default server_root */
       if (!GetCurrentDirectory(sizeof(cwd),cwd)) {
           ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), NULL, "GetCurrentDirectory() failure");
  @@ -260,7 +317,7 @@
        * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath
        */
       if (isProcessService()) {
  -        service_main(apache_main, argc, argv);
  +        servicent_main(apache_main, argc, argv);
           cleanup_and_exit();
       }
   
  @@ -278,7 +335,7 @@
               break;
           case 'n':
               service_name = ap_pstrdup(pwincmd, ap_optarg);
  -            if (isValidService(ap_optarg)) {
  +            if (isValidService(pwincmd, ap_optarg)) {
                   ap_registry_get_service_conf(pwincmd, &server_confname, ap_optarg);
               }
               break;
  @@ -302,6 +359,12 @@
           }
       }
   
  +    /* Set optreset and optind to allow ap_getopt to work correctly
  +     * when called from http_main.c
  +     */
  +    ap_optreset = 1;
  +    ap_optind = 1;
  +
       /* Determine server_confname. 
        * server_confname is found in this order:
        * (1) -f or -n
  @@ -343,20 +406,23 @@
       if (install) {
           if (!service_name)
               service_name = DEFAULTSERVICENAME;
  -        InstallService(service_name, server_confname);
  +        InstallServiceNT(service_name, server_confname);
           cleanup_and_exit();
       }
       /* Handle -u (uninstall service) */
       if (uninstall) {
           if (!service_name)
               service_name = DEFAULTSERVICENAME;
  -        RemoveService(service_name);
  +        RemoveServiceNT(service_name);
           cleanup_and_exit();
       }
   
       /* Handle -k startservice */
       if (signal && !strcasecmp(signal, "startservice")) {
  -        service95_main(apache_main, argc, argv);
  +        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  +            service9x_main(apache_main, argc, argv);
  +        else
  +            servicent_main(apache_main, argc, argv);
           cleanup_and_exit();
       }
   
  @@ -394,18 +460,17 @@
       *new = server_root;
       new_argc += 4;    
   
  -    /* Set optreset and optind to allow ap_getopt to work correctly
  -     * when called from http_main.c
  -     */
  -    ap_optreset = 1;
  -    ap_optind = 1;
  -
       /* Proxy to delay console_control_handler hook until all is running */
       ap_mpm_init_complete = console_started_hook;
   
       rv = apache_main(new_argc, (char**) cmdtbl->elts);
   
  -    SetConsoleCtrlHandler(console_control_handler, FALSE);
  +    if (getenv("AP_PARENT_PID"))
  +        SetConsoleCtrlHandler(child_control_handler, FALSE);
  +    else
  +        SetConsoleCtrlHandler(console_control_handler, FALSE);
   
       return (rv);
   }
  +
  +#endif /* WIN32 */
  
  
  
  1.19      +2 -30     apache-2.0/src/os/win32/registry.c
  
  Index: registry.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/os/win32/registry.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- registry.c	2000/05/01 14:40:03	1.18
  +++ registry.c	2000/05/19 05:01:49	1.19
  @@ -101,6 +101,7 @@
   #define SERVICEKEYPRE  "System\\CurrentControlSet\\Services\\"
   #define SERVICEKEYPOST "\\Parameters"
   
  +#define SERVICELAUNCH9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices\\"
   /*
    * The Windows API registry key functions don't set the last error
    * value (the windows equivalent of errno). So we need to set it
  @@ -253,19 +254,6 @@
    * dir will contain an empty string), or -1 if there was
    * an error getting the key.
    */
  -#if 0
  -int ap_registry_get_server_root(ap_pool_t *p, char *dir, int size)
  -{
  -    int rv;
  -
  -    rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL);
  -    if (rv < 0) {
  -	dir[0] = '\0';
  -    }
  -
  -    return (rv < -1) ? -1 : 0;
  -}
  -#else
   int ap_registry_get_server_root(ap_pool_t *p, char **buf)
   {
       int rv;
  @@ -277,7 +265,7 @@
   
       return (rv < -1) ? -1 : 0;
   }
  -#endif
  +
   char *ap_get_service_key(char *display_name)
   {
       size_t keylen = strlen(display_name);
  @@ -290,21 +278,7 @@
       
       return(key);
   }
  -#if 0
  -int ap_registry_get_service_conf(ap_pool_t *p, char *dir, int size, char *display_name)
  -{
  -    int rv;
  -    char *key = ap_get_service_key(display_name);
  -
  -    rv = ap_registry_get_key_int(p, key, "ConfPath", dir, size, NULL);
  -    if (rv < 0) {
  -    dir[0] = '\0';
  -    }
   
  -    free(key);
  -    return (rv < -1) ? -1 : 0;
  -}
  -#else
   int ap_registry_get_service_conf(ap_pool_t *p, char **buf, char *service_name)
   {
       int rv;
  @@ -318,7 +292,6 @@
       free(key);
       return (rv < -1) ? -1 : 0;
   }
  -#endif
   
   /**********************************************************************
    * The rest of this file deals with storing keys or values in the registry
  @@ -552,4 +525,3 @@
   
       return rv < 0 ? -1 : 0;
   }
  -
  
  
  
  1.11      +139 -55   apache-2.0/src/os/win32/service.c
  
  Index: service.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/os/win32/service.c,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- service.c	2000/05/17 00:35:21	1.10
  +++ service.c	2000/05/19 05:01:49	1.11
  @@ -58,21 +58,20 @@
   
   #ifdef WIN32
   
  -#include "os.h"
  -#include <stdlib.h>
  -#include <direct.h>
  -
   #define  CORE_PRIVATE 
  +
  +#include "main_win32.h"
   #include "httpd.h"
   #include "http_conf_globals.h"
   #include "http_log.h"
  -#include "http_main.h"
   #include "service.h"
   #include "registry.h"
   #include "ap_mpm.h"
  +#include "..\..\modules\mpm\winnt\winnt.h"
   
   typedef void (CALLBACK *ap_completion_t)();
   API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
  +API_VAR_IMPORT char *ap_server_argv0;
   
   static struct
   {
  @@ -85,6 +84,8 @@
       SERVICE_STATUS ssStatus;
       FILE *logFile;
       char *service_dir;
  +    HANDLE threadService;
  +    HANDLE threadMonitor;
   } globdat;
   
   static void WINAPI service_main_fn(DWORD, LPTSTR *);
  @@ -93,54 +94,137 @@
   static int ap_start_service(SC_HANDLE);
   static int ap_stop_service(SC_HANDLE);
   
  -static void CALLBACK report_service95_running()
  +static LRESULT CALLBACK MonitorWin9xWndProc(HWND hWnd, UINT msg, 
  +                                            WPARAM wParam, LPARAM lParam)
   {
  -    FreeConsole();
  +/* This is the WndProc procedure for our invisible window.
  + * When the user shuts down the system, this window is sent
  + * a signal WM_ENDSESSION. We clean up by signaling Apache
  + * to shut down, and idle until Apache's primary thread quits.
  + */
  +    if ((msg == WM_ENDSESSION) && (lParam != ENDSESSION_LOGOFF))
  +    {
  +        ap_start_shutdown();
  +	if (wParam)
  +	    WaitForSingleObject(globdat.threadService, 30000);
  +        return 0;
  +    }
  +    return (DefWindowProc(hWnd, msg, wParam, lParam));
  +}
   
  -    /* We do this only once, ever */
  -    ap_mpm_init_complete = NULL;
  +static DWORD WINAPI MonitorWin9xEvents(LPVOID initEvent)
  +{
  +/* When running on Windows 9x, the ConsoleCtrlHandler is _NOT_ 
  + * called when the system is shutdown.  So create an invisible 
  + * window to watch for the WM_ENDSESSION message, and watch for
  + * the WM_CLOSE message to shut the window down.
  + */
  +    WNDCLASS wc;
  +    HWND hwndMain;
  +
  +    wc.style         = CS_GLOBALCLASS;
  +    wc.lpfnWndProc   = MonitorWin9xWndProc; 
  +    wc.cbClsExtra    = 0;
  +    wc.cbWndExtra    = 0; 
  +    wc.hInstance     = NULL;
  +    wc.hIcon         = NULL;
  +    wc.hCursor       = NULL;
  +    wc.hbrBackground = NULL;
  +    wc.lpszMenuName  = NULL;
  +    wc.lpszClassName = "ApacheWin9xService";
  + 
  +    if (RegisterClass(&wc)) 
  +    {
  +        /* Create an invisible window */
  +        hwndMain = CreateWindow("ApacheWin9xService", "Apache", 
  + 	                        WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, 
  +                                CW_USEDEFAULT, CW_USEDEFAULT, 
  +                                CW_USEDEFAULT, CW_USEDEFAULT, 
  +                                NULL, NULL, NULL, NULL);
  +        if (hwndMain)
  +        {
  +	    MSG msg;
  +	    /* If we succeed, eliminate the console window.
  +             * Signal the parent we are all set up, and
  +             * watch the message queue while the window lives.
  +             */
  +	    FreeConsole();
  +            SetEvent((HANDLE) initEvent);
  +            while (GetMessage(&msg, NULL, 0, 0)) 
  +            {
  +                if (msg.message == WM_CLOSE)
  +                    DestroyWindow(hwndMain); 
  +                else {
  +	            TranslateMessage(&msg);
  +	            DispatchMessage(&msg);
  +                }
  +            }
  +            globdat.threadMonitor = 0;
  +            return(0);
  +        }
  +    }
  +    /* We failed or are soon to die... 
  +     * we won't need this much longer 
  +     */
  +    SetEvent((HANDLE) initEvent);
  +    globdat.threadMonitor = 0;
  +    return(0);
   }
   
  -int service95_main(int (*main_fn)(int, char **), int argc, char **argv )
  +static void CALLBACK report_service9x_running()
   {
  -    HINSTANCE hkernel;
  +}
  +
  +int service9x_main(int (*main_fn)(int, char **), int argc, char **argv )
  +{
       DWORD (WINAPI *RegisterServiceProcess)(DWORD, DWORD);
  +    HINSTANCE hkernel;
  +    DWORD threadId;
  +    
  +    globdat.threadService = GetCurrentThread();
       
       /* Obtain a handle to the kernel library */
       hkernel = LoadLibrary("KERNEL32.DLL");
  -    if (!hkernel)
  -        return -1;
  -    
  -    /* Find the RegisterServiceProcess function */
  -    RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
  -                             GetProcAddress(hkernel, "RegisterServiceProcess");
  -    if (RegisterServiceProcess == NULL)
  -        return -1;
  -	
  -    /* Register this process as a service */
  -    if (!RegisterServiceProcess((DWORD)NULL, 1))
  -        return -1;
  -
  -    /* Eliminate the console for the remainer of the service session */
  -    ap_mpm_init_complete = report_service95_running;
  +    if (hkernel) {
  +        /* Find the RegisterServiceProcess function */
  +        RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
  +                                 GetProcAddress(hkernel, "RegisterServiceProcess");
  +        if (RegisterServiceProcess) {
  +            if (RegisterServiceProcess((DWORD)NULL, 1)) {
  +                HANDLE installed = CreateEvent(NULL, FALSE, FALSE, NULL);
  +                globdat.threadMonitor = CreateThread(NULL, 0,
  +                                                     MonitorWin9xEvents, 
  +                                                     (LPVOID) installed,
  +                                                     0, &threadId);
  +                WaitForSingleObject(installed, 30000);
  +                CloseHandle(installed);
  +            }
  +        }
  +    }
   
       /* Run the service */
       globdat.exit_status = main_fn(argc, argv);
   
  +    /* Still have a thread & window to clean up, so signal now */
  +    if (globdat.threadMonitor)
  +    {
  +	PostThreadMessage(threadId, WM_CLOSE, 0, 0);
  +        WaitForSingleObject(globdat.threadMonitor, 30000);
  +    }
  +
       /* When the service quits, remove it from the 
          system service table */
  -    RegisterServiceProcess((DWORD)NULL, 0);
  +    if (RegisterServiceProcess)
  +	RegisterServiceProcess((DWORD)NULL, 0);
   
       /* Free the kernel library */
  -    // Worthless, methinks, since it won't be reclaimed
  -    // FreeLibrary(hkernel);
  +    if (hkernel)
  +        FreeLibrary(hkernel);
   
  -    /* We have to quit right here to avoid an invalid page fault */
  -    // But, this is worth experimenting with!
       return (globdat.exit_status);
   }
   
  -int service_main(int (*main_fn)(int, char **), int argc, char **argv )
  +int servicent_main(int (*main_fn)(int, char **), int argc, char **argv )
   {
       SERVICE_TABLE_ENTRY dispatchTable[] =
       {
  @@ -166,24 +250,12 @@
       }
   }
   
  -void service_cd()
  +static void CALLBACK report_servicent_started()
   {
  -    /* change to the drive with the executable */
  -    char buf[300];
  -    GetModuleFileName(NULL, buf, 300);
  -    buf[2] = 0;
  -    chdir(buf);
  -}
  -
  -static void CALLBACK report_service_started()
  -{
       ReportStatusToSCMgr(
           SERVICE_RUNNING,    // service state
           NO_ERROR,           // exit code
           0);                 // wait hint
  -    
  -    /* This is only reported once, ever! */
  -    ap_mpm_init_complete = NULL;
   }
   
   void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
  @@ -217,10 +289,8 @@
           SERVICE_START_PENDING, // service state
           NO_ERROR,              // exit code
           3000);                 // wait hint
  -
  -    ap_mpm_init_complete = report_service_started;
   
  -    service_cd();
  +    ap_mpm_init_complete = report_servicent_started;
   
       /* Fetch server_conf from the registry 
        *  Rebuild argv and argc adding the -d server_root and -f server_conf then 
  @@ -274,7 +344,6 @@
   {
       int state;
   
  -
       state = globdat.ssStatus.dwCurrentState;
       switch(dwCtrlCode)
       {
  @@ -342,7 +411,7 @@
       return(1);
   }
   
  -void InstallService(char *display_name, char *conf)
  +void InstallServiceNT(char *display_name, char *conf)
   {
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
  @@ -415,7 +484,7 @@
   }
   
   
  -void RemoveService(char *display_name)
  +void RemoveServiceNT(char *display_name)
   {
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
  @@ -473,16 +542,27 @@
   }
   
   /* Determine is service_name is a valid service
  + * Simplify by testing the registry rather than the SCM
  + * as this will work on both WinNT and Win9x.
    */
   
  -BOOL isValidService(char *display_name) {
  -    SC_HANDLE schSCM, schSVC;
  +BOOL isValidService(ap_pool_t *p, char *display_name) {
       char service_name[256];
  -    int Err;
  +    char *service_conf;
   
       /* Remove spaces from display name to create service name */
       ap_collapse_spaces(service_name, display_name);
   
  +    if(ap_registry_get_service_conf(p, &service_conf, service_name)) {
  +        return TRUE;
  +    }
  +    
  +    return FALSE;
  +
  +#if 0
  +    SC_HANDLE schSCM, schSVC;
  +    int Err;
  +
       if (!(schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
           ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), NULL,
                        "OpenSCManager failed");
  @@ -501,8 +581,12 @@
                        "OpenService failed");
   
       return FALSE;
  +#endif
   }
   
  +/* Although the Win9x service enhancement added -k startservice,
  + * it is never processed here, so we still ignore that param.
  + */
   int send_signal_to_service(char *display_name, char *sig) {
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
  @@ -607,6 +691,6 @@
               return TRUE;
       return FALSE;
   }
  -           
  +
   #endif /* WIN32 */
   
  
  
  
  1.5       +11 -8     apache-2.0/src/os/win32/service.h
  
  Index: service.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/os/win32/service.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- service.h	2000/05/17 00:35:21	1.4
  +++ service.h	2000/05/19 05:01:50	1.5
  @@ -60,16 +60,19 @@
   #define SERVICE_H
   
   #ifdef WIN32
  -int service_main(int (*main_fn)(int, char **), int argc, char **argv);
  -int service95_main(int (*main_fn)(int, char **), int argc, char **argv);
  -void service_set_status(int status);
  -void service_cd();
   BOOL isProcessService();
  -BOOL isValidService(char *display_name);
  -void InstallService(char *display_name, char *conf);
  -void RemoveService(char *display_name);
  -int service_init();
  +BOOL isValidService(ap_pool_t *p, char *display_name);
   int send_signal_to_service(char *display_name, char *sig);
  +
  +int service9x_main(int (*main_fn)(int, char **), int argc, char **argv);
  +
  +int servicent_main(int (*main_fn)(int, char **), int argc, char **argv);
  +void InstallServiceNT(char *display_name, char *conf);
  +void RemoveServiceNT(char *display_name);
  +
  +//void service_set_status(int status);
  +//void service_cd();
  +//int service_init();
   #endif /* WIN32 */
   
   #endif /* SERVICE_H */
  
  
  
  1.1                  apache-2.0/src/os/win32/main_win32.h
  
  Index: main_win32.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  
  /*
   * Declarations for users of the functions defined in registry.c
   */
  
  #ifndef _WIN32_WINNT
  #define _WIN32_WINNT 0x0400
  #endif
  #ifndef NOGDI
  #define NOGDI
  #endif
  #ifndef NONLS
  #define NONLS
  #endif
  #ifndef NOMCX
  #define NOMCX
  #endif
  #ifndef NOIME
  #define NOIME
  #endif
  #include <windows.h>
  #include <winsock2.h>
  #include <mswsock.h>
  
  
  
  1.12      +1 -0      apache-2.0/src/include/ap_listen.h
  
  Index: ap_listen.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/ap_listen.h,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- ap_listen.h	2000/03/31 07:18:52	1.11
  +++ ap_listen.h	2000/05/19 05:01:52	1.12
  @@ -56,6 +56,7 @@
   #define AP_LISTEN_H
   
   #include "apr_network_io.h"
  +#include "http_config.h"
   
   typedef struct ap_listen_rec ap_listen_rec;
   struct ap_listen_rec {
  
  
  
  1.7       +4 -0      apache-2.0/src/include/http_main.h
  
  Index: http_main.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/http_main.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- http_main.h	2000/03/31 07:18:59	1.6
  +++ http_main.h	2000/05/19 05:01:52	1.7
  @@ -71,6 +71,10 @@
   extern ap_array_header_t *ap_server_post_read_config;
   extern ap_array_header_t *ap_server_config_defines;
   
  +#ifdef WIN32
  +API_EXPORT(int) apache_main(int argc, char *argv[]);
  +#endif
  +
   #ifdef __cplusplus
   }
   #endif
  
  
  
  1.11      +0 -1      apache-2.0/src/lib/apr/include/apr.hw
  
  Index: apr.hw
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr.hw,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- apr.hw	2000/05/18 02:17:22	1.10
  +++ apr.hw	2000/05/19 05:01:52	1.11
  @@ -91,7 +91,6 @@
   #define NOIME
   #endif
   #include <windows.h>
  -#include <windows.h>
   /* 
    * Add a _very_few_ declarations missing from the restricted set of headers
    * (If this list becomes extensive, re-enable the required headers above!)
  
  
  
  1.29      +3 -1      apache-2.0/src/lib/apr/threadproc/win32/proc.c
  
  Index: proc.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/lib/apr/threadproc/win32/proc.c,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- proc.c	2000/05/01 03:24:35	1.28
  +++ proc.c	2000/05/19 05:01:52	1.29
  @@ -340,7 +340,9 @@
               pNext = pNext + strlen(pNext) + 1;
               i++;
           }
  -        strcpy(pNext, envstr);        
  +        strcpy(pNext, envstr); 
  +	pNext = pNext + strlen(pNext) + 1;
  +	*pNext = '\0';
       }
       else {
           SetEnvironmentVariable("parentpid", ppid);
  
  
  
  1.67      +43 -13    apache-2.0/src/modules/mpm/winnt/winnt.c
  
  Index: winnt.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/winnt/winnt.c,v
  retrieving revision 1.66
  retrieving revision 1.67
  diff -u -r1.66 -r1.67
  --- winnt.c	2000/05/17 00:35:19	1.66
  +++ winnt.c	2000/05/19 05:01:53	1.67
  @@ -68,11 +68,9 @@
   #include "ap_config.h"
   #include "ap_listen.h"
   #include "mpm_default.h"
  -//#include "service.h"
   #include "iol_socket.h"
   #include "winnt.h"
   
  -
   /*
    * Definitions of WINNT MPM specific config globals
    */
  @@ -105,9 +103,8 @@
   static event *exit_event;
   HANDLE maintenance_event;
   ap_lock_t *start_mutex;
  -int my_pid;
  -int parent_pid;
  -typedef void (CALLBACK *ap_completion_t)();
  +DWORD my_pid;
  +DWORD parent_pid;
   API_VAR_EXPORT ap_completion_t ap_mpm_init_complete = NULL;
   
   static ap_status_t socket_cleanup(void *sock)
  @@ -299,15 +296,19 @@
       }
       CloseHandle(e);
   }
  +
   static int volatile is_graceful = 0;
  +
   API_EXPORT(int) ap_graceful_stop_signalled(void)
   {
       return is_graceful;
   }
  -void ap_start_shutdown(void)
  +
  +API_EXPORT(void) ap_start_shutdown(void)
   {
       signal_parent(0);
   }
  +
   /*
    * Initialise the signal names, in the global variables signal_name_prefix, 
    * signal_restart_name and signal_shutdown_name.
  @@ -354,6 +355,7 @@
    * Routines to deal with managing the list of listening sockets.
    */
   static ap_listen_rec *head_listener;
  +
   static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
   {
       ap_listen_rec *lr;
  @@ -371,6 +373,7 @@
       }
       return NULL;
   }
  +
   static int setup_listeners(server_rec *s)
   {
       ap_listen_rec *lr;
  @@ -1390,7 +1393,10 @@
       int rv;
       char buf[1024];
       char *pCommand;
  +    char *pEnvVar;
  +    char *pEnvBlock;
       int i;
  +    int iEnvBlockLen;
       STARTUPINFO si;           /* Filled in prior to call to CreateProcess */
       PROCESS_INFORMATION pi;   /* filled in on call to CreateProces */
   
  @@ -1425,6 +1431,32 @@
           pCommand = ap_pstrcat(p, pCommand, " \"", server_conf->process->argv[i], "\"", NULL);
       }
   
  +    /* Build the environment, since Win9x disrespects the active env */
  +    // SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%l",parent_pid));
  +    pEnvVar = ap_psprintf(p, "AP_PARENT_PID=%i", parent_pid);
  +    /*
  +     * Win32's CreateProcess call requires that the environment
  +     * be passed in an environment block, a null terminated block of
  +     * null terminated strings.
  +     */  
  +    i = 0;
  +    iEnvBlockLen = 1;
  +    while (_environ[i]) {
  +        iEnvBlockLen += strlen(_environ[i]) + 1;
  +        i++;
  +    }
  +
  +    pEnvBlock = (char *)ap_pcalloc(p, iEnvBlockLen + strlen(pEnvVar) + 1);
  +    strcpy(pEnvBlock, pEnvVar);
  +    pEnvVar = strchr(pEnvBlock, '\0') + 1;
  +
  +    i = 0;
  +    while (_environ[i]) {
  +        strcpy(pEnvVar, _environ[i]);
  +        pEnvVar = strchr(pEnvVar, '\0') + 1;
  +        i++;
  +    }
  +    pEnvVar = '\0';
       /* Create a pipe to send socket info to the child */
       if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) {
           ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
  @@ -1432,8 +1464,6 @@
           return -1;
       }
   
  -    SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%d",parent_pid));
  -
       /* Give the read end of the pipe (hPipeRead) to the child as stdin. The 
        * parent will write the socket data to the child on this pipe.
        */
  @@ -1447,7 +1477,7 @@
       if (!CreateProcess(NULL, pCommand, NULL, NULL, 
                          TRUE,               /* Inherit handles */
                          CREATE_SUSPENDED,   /* Creation flags */
  -                       NULL,               /* Environment block */
  +                       pEnvBlock,          /* Environment block */
                          NULL,
                          &si, &pi)) {
           ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
  @@ -1694,12 +1724,12 @@
       pid = getenv("AP_PARENT_PID");
       if (pid) {
           /* This is the child */
  -        parent_pid = atoi(pid);
  -        my_pid = getpid();
  +        parent_pid = (DWORD) atol(pid);
  +        my_pid = GetCurrentProcessId();
       }
       else {
           /* This is the parent */
  -        parent_pid = my_pid = getpid();
  +        parent_pid = my_pid = GetCurrentProcessId();
       }
   
       ap_listen_pre_config();
  @@ -1806,7 +1836,7 @@
               if (pidfile != NULL && unlink(pidfile) == 0) {
                   ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,APR_SUCCESS,
                                server_conf, "removed PID file %s (pid=%ld)",
  -                             pidfile, (long)getpid());
  +                             pidfile, GetCurrentProcessId());
               }
               ap_destroy_lock(start_mutex);
   
  
  
  
  1.11      +6 -0      apache-2.0/src/modules/mpm/winnt/winnt.h
  
  Index: winnt.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/winnt/winnt.h,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- winnt.h	2000/04/14 15:59:04	1.10
  +++ winnt.h	2000/05/19 05:01:53	1.11
  @@ -59,11 +59,17 @@
   #ifndef APACHE_MPM_WINNT_H
   #define APACHE_MPM_WINNT_H
   
  +#include "ap_listen.h"
  +
   extern int ap_threads_per_child;
   extern int ap_max_requests_per_child;
   extern int ap_extended_status;
   extern void clean_child_exit(int);
   
  +typedef void (CALLBACK *ap_completion_t)();
  +API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
  +
  +API_EXPORT(void) ap_start_shutdown(void);
   
   typedef struct CompContext {
       OVERLAPPED Overlapped;