httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@locus.apache.org
Subject cvs commit: apache-1.3/src/os/win32 service.c
Date Mon, 12 Jun 2000 21:50:03 GMT
wrowe       00/06/12 14:50:00

  Modified:    src/main http_main.c
               src/include http_main.h
               src/os/win32 service.c
  Log:
    This change should address all remaining service control issues.
  
    1) The code path is cleaned up, and much more Win32 code is moved
       into #ifdef WIN32 blocks.  This should only affect OS2/Netware,
       or other rare multithreaded beasts.
  
    2) A significant amount of Win32 service and console code is moved
       to os/win32/services.c from http_main.c
  
    3) The create_process() no longer passes -n or -k arguments, leaving
       the child processes free to do their real work.
  
    4) Move Win9x service control (-k args) to follow the WinNT path.
       All except to actually -k start or -k restart (from stopped state.)
       Win9x can -k shutdown even when the pid file is whacked by starting
       console Apache.
  
    5) Emulate service engine under Win9x by traversing the list of hidden
       ApacheService windows for the specified service.  Prevents starting
       two copies of a Win9x service, and allows positive confirmation of
       Win9x service shutdown.
  
    6) Best of all, -k restart -really- restarts the server gracefully,
       even in the case of windows NT services.
  
  Revision  Changes    Path
  1.500     +39 -27    apache-1.3/src/main/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_main.c,v
  retrieving revision 1.499
  retrieving revision 1.500
  diff -u -r1.499 -r1.500
  --- http_main.c	2000/06/12 07:02:17	1.499
  +++ http_main.c	2000/06/12 21:49:45	1.500
  @@ -6150,7 +6150,10 @@
       pCommand = ap_psprintf(p, "\"%s\" -Z %s -f \"%s\"", buf, exit_event_name, ap_server_confname);
 
   
       for (i = 1; i < argc; i++) {
  -        pCommand = ap_pstrcat(p, pCommand, " \"", argv[i], "\"", NULL);
  +        if ((argv[i][0] == '-') && ((argv[i][1] == 'k') || (argv[i][1] == 'n')))
  +            ++i;
  +        else
  +            pCommand = ap_pstrcat(p, pCommand, " \"", argv[i], "\"", NULL);
       }
   
       /* Create a pipe to send socket info to the child */
  @@ -6602,25 +6605,25 @@
       int child = 0;
       char *cp;
       char *s;
  +    int conf_specified = 0;
  +    char cwd[MAX_STRING_LEN];
  +
  +#ifdef WIN32
       char *service_name = NULL;
       int install = 0;
  -    int conf_specified = 0;
       char *signal_to_send = NULL;
  -    char cwd[MAX_STRING_LEN];
  +
  +    /* Service application under WinNT */
  +    if (isWindowsNT() && isProcessService()) {
  +        service_main(master_main, argc, argv);
  +        clean_parent_exit(0);
  +    }
  +#endif
   
   #ifdef NETWARE
       init_name_space();
       signal(SIGTERM, signal_handler);
       init_tsd();
  -#else
  -    /* Service application
  -     * Configuration file in registry at:
  -     * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath
  -     */
  -    if (isProcessService()) {
  -        service_main(master_main, argc, argv);
  -        clean_parent_exit(0);
  -    }
   #endif
   
       /* Console application or a child process. */
  @@ -6822,8 +6825,8 @@
        * or shutting down a running service 
        * (but do read the conf for the pidfile if we shutdown the console)
        */
  -    if ((install >= 0) && (!service_name || !signal_to_send || !isWindowsNT()
  -                           || strcasecmp(signal_to_send,"shutdown"))) {
  +    if ((install >= 0) && (!service_name || !signal_to_send 
  +                            || strcasecmp(signal_to_send,"shutdown"))) {
           server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
       }
   
  @@ -6837,17 +6840,21 @@
               RemoveService(service_name);
           clean_parent_exit(0);
       }
  -    
  -    if (service_name && signal_to_send && isWindowsNT()) {
  -        send_signal_to_service(service_name, signal_to_send);
  -        clean_parent_exit(0);
  -    }
   
       if (service_name && !conf_specified) {
           printf("Unknown service: %s\n", service_name);
           clean_parent_exit(0);
       }
  -#else
  +
  +    /* All NT signals, and all but the 9x start signal are handled entirely.
  +     * Die if we failed, are on NT, or are not "start"ing the service
  +     */
  +    if (service_name && signal_to_send) {
  +        if (!send_signal_to_service(service_name, signal_to_send)
  +                || isWindowsNT() || strcasecmp(signal_to_send, "start"))
  +            clean_parent_exit(0);
  +    }
  +#else /* ndef WIN32 */
       server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
   #endif
   
  @@ -6861,13 +6868,13 @@
       }
   
   #ifdef WIN32
  -    /* Handle -k start [with or without -n arg] later */
  +    /* Non-service Signals.  (Ignore -k start for now [with or without -n arg]) */
       if (signal_to_send && strcasecmp(signal_to_send, "start")) {
           send_signal(pconf, signal_to_send);
           clean_parent_exit(0);
       }
   #endif
  -    
  +
   #ifndef NETWARE
       if (!child && !ap_dump_settings) { 
           ap_log_pid(pconf, ap_pid_fname);
  @@ -6900,7 +6907,7 @@
   
       while((ap_thread_count) || (!shutdown_pending))
           ThreadSwitchWithDelay();
  -#else
  +#else 
       /*
        * In the future, the main will spawn off a couple
        * of children and monitor them. As soon as a child
  @@ -6917,6 +6924,7 @@
   	ap_destroy_mutex(start_mutex);
   	destroy_event(exit_event);
       } 
  +#ifdef WIN32
       else if (service_name && signal_to_send && !isWindowsNT()
                && !strcasecmp(signal_to_send, "start")) {
           /* service95_main will call master_main() */
  @@ -6924,14 +6932,18 @@
       }
       else 
       {
  -#ifdef WIN32
  -	/* Let's go fishing for some signals including ctrl+c,
  -         * ctrl+break, logoff, close and shutdown.
  +	/* Let's go fishing for some signals including ctrl+c, ctrl+break,
  +         * logoff, close and shutdown, while the server is running
   	 */
   	ap_start_console_monitor();
  -#endif /* WIN32 */
           master_main(argc, argv);
       }
  +#else /* ndef WIN32 */
  +    else 
  +    {
  +        master_main(argc, argv);
  +    }
  +#endif /* ndef WIN32 */
   #endif /* ndef NETWARE */
   
       clean_parent_exit(0);
  
  
  
  1.32      +2 -0      apache-1.3/src/include/http_main.h
  
  Index: http_main.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/http_main.h,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- http_main.h	1999/01/01 19:04:40	1.31
  +++ http_main.h	2000/06/12 21:49:53	1.32
  @@ -127,6 +127,8 @@
   unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x);
   API_EXPORT(int) ap_check_alarm(void);
   
  +void setup_signal_names(char *prefix);
  +
   #ifndef NO_OTHER_CHILD
   /*
    * register an other_child -- a child which the main loop keeps track of
  
  
  
  1.21      +175 -54   apache-1.3/src/os/win32/service.c
  
  Index: service.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/os/win32/service.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- service.c	2000/06/12 04:38:04	1.20
  +++ service.c	2000/06/12 21:49:57	1.21
  @@ -14,6 +14,8 @@
   #include "service.h"
   #include "registry.h"
   
  +#define SERVICE_APACHE_RESTART 128
  +
   static struct
   {
       int (*main_fn)(int, char **);
  @@ -32,12 +34,12 @@
   DWORD (WINAPI *RegisterServiceProcess)(DWORD, DWORD);
   HINSTANCE    monitor_hkernel = NULL;
   
  -
   static void WINAPI service_main_fn(DWORD, LPTSTR *);
   static void WINAPI service_ctrl(DWORD ctrlCode);
   static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint);
   static int ap_start_service(SC_HANDLE);
   static int ap_stop_service(SC_HANDLE);
  +static int ap_restart_service(SC_HANDLE);
   
   int service_main(int (*main_fn)(int, char **), int argc, char **argv )
   {
  @@ -276,6 +278,11 @@
   	    ap_start_shutdown();
               break;
   
  +        case SERVICE_APACHE_RESTART:
  +            state = SERVICE_START_PENDING;
  +	    ap_start_restart(1);
  +            break;
  +
           // Update the service status.
           //
           case SERVICE_CONTROL_INTERROGATE:
  @@ -581,17 +588,25 @@
   
   BOOL isWindowsNT(void)
   {
  -    OSVERSIONINFO osver;
  -    osver.dwOSVersionInfoSize = sizeof(osver);
  -
  -    if (GetVersionEx(&osver))
  -        if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
  -            return TRUE;
  -
  -    return FALSE;
  +    static BOOL once = FALSE;
  +    static BOOL isNT = FALSE;
  +    
  +    if (!once) 
  +    {
  +        OSVERSIONINFO osver;
  +        osver.dwOSVersionInfoSize = sizeof(osver);
  +        if (GetVersionEx(&osver))
  +            if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
  +                isNT = TRUE;
  +        once = TRUE;
  +    }
  +    return isNT;
   }
   
  -int send_signal_to_service(char *display_name, char *sig) {
  +int send_signal_to_service(char *display_name, char *sig) 
  +{
  +    DWORD       service_pid;
  +    HANDLE      hwnd;
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
       char       *service_name;
  @@ -615,50 +630,117 @@
       service_name = strdup(display_name);
       ap_remove_spaces(service_name, display_name);
   
  -    schSCManager = OpenSCManager(
  -                        NULL,                   // machine (NULL == local)
  -                        NULL,                   // database (NULL == default)
  -                        SC_MANAGER_ALL_ACCESS   // access required
  -                        );
  -    if (!schSCManager) {
  -        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  -        "OpenSCManager failed");
  -    }
  -    else {
  +    if (isWindowsNT()) 
  +    {
  +        schSCManager = OpenSCManager(
  +                            NULL,                   // machine (NULL == local)
  +                            NULL,                   // database (NULL == default)
  +                            SC_MANAGER_ALL_ACCESS   // access required
  +                            );
  +        if (!schSCManager) {
  +            ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +                         "OpenSCManager failed");
  +            return FALSE;
  +        }
  +        
           schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
   
           if (schService == NULL) {
               /* Could not open the service */
  -           ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  -            "OpenService failed");
  +            ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +                         "OpenService failed");
  +            CloseServiceHandle(schSCManager);
  +            return FALSE;
           }
  -        else {
  -            if (!QueryServiceStatus(schService, &globdat.ssStatus))
  -                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  -                             "QueryService failed");
  -            else {
  -                if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED && action
== stop)
  -                    printf("The %s service is not started.\n", display_name);
  -                else if (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING &&
action == start)
  -                    printf("The %s service has already been started.\n", display_name);
  -                else {
  -                    printf("The %s service is %s.\n", display_name, participle[action]);
  -
  -                    if (action == stop || action == restart)
  -                        success = ap_stop_service(schService);
  -                    if (action == start || action == restart)
  -                        success = ap_start_service(schService);
  -                
  -                    if( success )
  -                        printf("The %s service has %s.\n", display_name, past[action]);
  +        
  +        if (!QueryServiceStatus(schService, &globdat.ssStatus)) {
  +            ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +                         "QueryService failed");
  +            CloseServiceHandle(schService);
  +            CloseServiceHandle(schSCManager);
  +        }
  +    }
  +    else /* !isWindowsNT() */
  +    {
  +        /* Locate the window named service_name of class ApacheWin95ServiceMonitor
  +         * from the active top level windows
  +         */
  +        hwnd = FindWindow("ApacheWin95ServiceMonitor", service_name);
  +        if (hwnd && GetWindowThreadProcessId(hwnd, &service_pid))
  +            globdat.ssStatus.dwCurrentState = SERVICE_RUNNING;
  +        else
  +            globdat.ssStatus.dwCurrentState = SERVICE_STOPPED;
  +    }
  +
  +    if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED 
  +            && action == stop) {
  +        printf("The %s service is not started.\n", display_name);
  +    }
  +    else if (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING 
  +                 && action == start) {
  +       printf("The %s service has already been started.\n", display_name);
  +    }
  +    else
  +    {
  +        printf("The %s service is %s.\n", display_name, participle[action]);
  +
  +        if (isWindowsNT()) 
  +        {
  +            if (action == stop)
  +                success = ap_stop_service(schService);
  +            else if ((action == start) 
  +                     || ((action == restart) 
  +                            && (globdat.ssStatus.dwCurrentState 
  +                                    == SERVICE_STOPPED)))
  +                success = ap_start_service(schService);
  +            else if (action == restart)
  +                success = ap_restart_service(schService);
  +        }
  +        else /* !isWindowsNT()) */
  +        {
  +            char prefix[20];
  +            ap_snprintf(prefix, sizeof(prefix), "ap%ld", (long)service_pid);
  +            setup_signal_names(prefix);
  +
  +            if (action == stop) {
  +                int ticks = 60;
  +                ap_start_shutdown();
  +                while (--ticks)
  +                {
  +                    if (!IsWindow(hwnd)) {
  +                        success = TRUE;
  +                        break;
  +                    }
  +                    Sleep(1000);
  +                }
  +            }
  +            else /* !stop */
  +            {   
  +                /* This gets a bit tricky... start and restart (of stopped service)
  +                 * will simply fall through and *THIS* process will fade into an
  +                 * invisible 'service' process, detaching from the user's console.
  +                 * We need to change the restart signal to "start", however,
  +                 * if the service was not -yet- running.
  +                 */
  +                if (action == restart) 
  +                {
  +                    if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) 
  +                        strcpy(sig, "start");
                       else
  -                        printf("Failed to %s the %s service.\n", sig, display_name);
  +                        ap_start_restart(1);
                   }
  -
  -                CloseServiceHandle(schService);
  +                success = TRUE;
               }
           }
  -        /* SCM removes registry parameters */
  +
  +        if( success )
  +            printf("The %s service has %s.\n", display_name, past[action]);
  +        else
  +            printf("Failed to %s the %s service.\n", sig, display_name);
  +    }
  +
  +    if (isWindowsNT()) {
  +        CloseServiceHandle(schService);
           CloseServiceHandle(schSCManager);
       }
       return success;
  @@ -697,6 +779,26 @@
       return FALSE;
   }
   
  +int ap_restart_service(SC_HANDLE schService) 
  +{
  +    int ticks;
  +    if (ControlService(schService, SERVICE_APACHE_RESTART, &globdat.ssStatus)) 
  +    {
  +        ticks = 60;
  +        while (globdat.ssStatus.dwCurrentState == SERVICE_START_PENDING)
  +        {
  +            Sleep(1000);
  +            if (!QueryServiceStatus(schService, &globdat.ssStatus)) 
  +                return FALSE;
  +            if (!--ticks)
  +                break;
  +        }
  +    }
  +    if (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)
  +        return TRUE;
  +    return FALSE;
  +}
  +
   /* Control handler for processing Ctrl-C/Ctrl-Break and
    * on Windows NT also user logoff and system shutdown
    */
  @@ -744,19 +846,38 @@
   
   void ap_start_console_monitor(void)
   {
  -    /* Under Windows NT, assure we properly accept Ctrl+C as an interrupt...
  -     * Win/2000 definately makes the wrong assumption here, 
  -     * disabling ctrl+c by default!
  +    HANDLE console_input;
  +    
  +    console_input = GetStdHandle(STD_INPUT_HANDLE);
  +    /* Assure we properly accept Ctrl+C as an interrupt...
  +     * Win/2000 definately makes some odd assumptions about 
  +     * ctrl+c and the reserved console mode bits!
        */
  -    if (isWindowsNT()) {
  -	SetConsoleCtrlHandler(NULL, FALSE);
  +    if (console_input != INVALID_HANDLE_VALUE)
  +    {
  +        /* The SetConsoleCtrlHandler(NULL... would fault under Win9x 
  +         * WinNT also includes an undocumented 0x80 bit for console mode
  +         * that preserves the console window behavior, and prevents the
  +         * bogus 'selection' mode from being accedently triggered.
  +         */
  +        if (isWindowsNT()) {
  +	    SetConsoleCtrlHandler(NULL, FALSE);
  +            SetConsoleMode(console_input, ENABLE_LINE_INPUT 
  +                                        | ENABLE_ECHO_INPUT 
  +                                        | ENABLE_PROCESSED_INPUT
  +                                        | 0x80);
  +        }
  +	else {
  +            SetConsoleMode(console_input, ENABLE_LINE_INPUT 
  +                                        | ENABLE_ECHO_INPUT 
  +                                        | ENABLE_PROCESSED_INPUT);
  +        }
  +        SetConsoleCtrlHandler(ap_control_handler, TRUE);
       }
  -
  +    
       /* Under 95/98 create a monitor window to watch for session end,
  -     * pass NULL to WatchWindow so we do not appear to run as a service.
  +     * pass NULL to WatchWindow so we do not appear to be a service.
        */
  -    SetConsoleCtrlHandler(ap_control_handler, TRUE);
  -    
       if (!isWindowsNT()) {
           HANDLE thread;
           thread = CreateThread(NULL, 0, WatchWindow, NULL, 0, 
  
  
  

Mime
View raw message