mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Ludovic Poitou
08.26.2013 bce0666db7ec0fd758c781cd3db6ea493f78d408
Fix for OPENDJ-617.
Resolve race condition in Windows Services when stopping the server.
8 files modified
155 ■■■■■ changed files
opends/lib/launcher_administrator.exe patch | view | raw | blame | history
opends/lib/opendj_service.exe patch | view | raw | blame | history
opends/lib/winlauncher.exe patch | view | raw | blame | history
opends/src/build-tools/windows/service.c 115 ●●●● patch | view | raw | blame | history
opends/src/build-tools/windows/service.h 2 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ConfigureWindowsService.java 13 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StartWindowsService.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/StopWindowsService.java 21 ●●●● patch | view | raw | blame | history
opends/lib/launcher_administrator.exe
Binary files differ
opends/lib/opendj_service.exe
Binary files differ
opends/lib/winlauncher.exe
Binary files differ
opends/src/build-tools/windows/service.c
@@ -23,7 +23,7 @@
*
*
*      Copyright 2008-2010 Sun Microsystems, Inc.
*      Portions Copyright 2011 ForgeRock AS
*      Portions Copyright 2011-2013 ForgeRock AS
*/
#include "service.h"
@@ -527,7 +527,7 @@
  if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
  {
    sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath);
  sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath);
    debug("doStartApplication: Launching batch file: %s", command);
    createOk = createBatchFileChildProcess(command, FALSE, &procInfo);
@@ -572,14 +572,14 @@
      debug("The batch file process could not be created property");
    }
    if (createOk && waitOk)
  if (createOk && waitOk)
    {
      BOOL running;
    BOOL running;
      // Just check once if the server is running or not: since the wait
      // wait was successful, if the server is getting the lock, it already
      // got it.
      isServerRunning(&running, TRUE);
      if (running)
    isServerRunning(&running, TRUE);
    if (running)
      {
        returnValue = SERVICE_RETURN_OK;
        debug("doStartApplication: server running.");
@@ -589,7 +589,7 @@
        returnValue = SERVICE_RETURN_ERROR;
        debug("doStartApplication: server not running.");
      }
    }
  }
    else if (createOk)
    {
      // Try to see if server is really running
@@ -609,7 +609,7 @@
      else
      {
        debug("OPENDJ_WINDOWS_SERVICE_START_NTRIES is not set.  Using default %d tries.", nTries);
      }
      }
      debug(
          "doStartApplication: the spawn of the batch command worked.  Command: '%s'",
@@ -658,7 +658,7 @@
// ----------------------------------------------------
// Start the application using stop-ds.bat
// Stop the application using stop-ds.bat
// The functions returns SERVICE_RETURN_OK if we could stop the server
// and SERVICE_RETURN_ERROR otherwise.
// ----------------------------------------------------
@@ -751,7 +751,7 @@
  {
    // failed to get the path of the executable file
    returnValue = SERVICE_RETURN_ERROR;
    debug("Could not get the path of the executable file.");
  debug("Could not get the path of the executable file.");
  }
  else
  {
@@ -956,6 +956,53 @@
}  // updateServiceStatus
// ----------------------------------------------------
// Query the current status of the service serviceName into returnedStatus
// return true if it was successful, false otherwise
// ----------------------------------------------------
BOOL getServiceStatus(char *serviceName, LPDWORD returnedState)
{
  SC_HANDLE hScm;
  SC_HANDLE hService;
  BOOL ret = FALSE;
  if (openScm(SC_MANAGER_ALL_ACCESS, &hScm) != SERVICE_RETURN_OK)
  {
    debugError("getServiceStatus: openScm did not work. Last error = %d",
    GetLastError());
    return FALSE;
  }
  hService = OpenService(hScm, serviceName, SERVICE_QUERY_STATUS);
  if(hService == NULL)
  {
    debugError("getServiceStatus: openService did not work. Last error = %d",
      GetLastError());
  }
  else
  {
    SERVICE_STATUS ss;
    memset(&ss, 0, sizeof(ss));
    if (QueryServiceStatus(hService, &ss))
    {
      *returnedState = ss.dwCurrentState;
    ret = TRUE;
  }
  else
  {
    debugError("getServiceStatus: Failed to query the service status. Last error = %d",
                  GetLastError());
    }
    // close the service handle
    CloseServiceHandle(hService);
  }
  // close the service control manager handle
  CloseServiceHandle(hScm);
  return ret;
}
// ----------------------------------------------------
// This function is the "main" of the service. It has been registered
// to the SCM by the main right after the service has been started through
// NET START command.
@@ -1090,7 +1137,7 @@
  if (code == SERVICE_RETURN_OK)
  {
    BOOL updatedRunningStatus = FALSE;
    DWORD returnValue;
  DWORD returnValue;
    int refreshPeriodSeconds = 10;
    char *refreshPeriodEnv = getenv("OPENDJ_WINDOWS_SERVICE_REFRESH_PERIOD");
    if (refreshPeriodEnv != NULL)
@@ -1108,7 +1155,7 @@
      {
        returnValue = WaitForSingleObject (_terminationEvent, INFINITE);
        break;
      }
      }
      else
      {
        running = FALSE;
@@ -1123,7 +1170,7 @@
          if (returnValue == WAIT_OBJECT_0)
          {
            debug("The application has exited.");
            break;
            break;
          }
        }
        code = isServerRunning(&running, FALSE);
@@ -1134,16 +1181,16 @@
        else if (running)
        {
          _serviceCurStatus = SERVICE_RUNNING;
          if (!updatedRunningStatus)
          {
            WORD argCount = 1;
      if (!updatedRunningStatus)
      {
        WORD argCount = 1;
            const char *argc[] = {_instanceDir};
            updateServiceStatus (
               _serviceCurStatus,
               NO_ERROR,
               0,
               checkPoint ++,
               TIMEOUT_NONE,
           TIMEOUT_NONE,
               _serviceStatusHandle
             );
             reportLogEvent(
@@ -1151,27 +1198,35 @@
               WIN_EVENT_ID_SERVER_STARTED,
               argCount, argc
             );
             updatedRunningStatus = TRUE;
          }
       updatedRunningStatus = TRUE;
      }
        }
        else
        {
          WORD argCount = 1;
          const char *argc[] = {_instanceDir};
          _serviceCurStatus = SERVICE_STOPPED;
          debug("checking in serviceMain serviceHandler: service stopped.");
      // Check current Status
      DWORD state;
      BOOL success = getServiceStatus(serviceName, &state);
          if (!(success &&
               ((state == SERVICE_STOPPED) ||
                (state == SERVICE_STOP_PENDING))))
          {
          WORD argCount = 1;
            const char *argc[] = {_instanceDir};
            _serviceCurStatus = SERVICE_STOPPED;
            debug("checking in serviceMain serviceHandler: service stopped with error.");
          updateServiceStatus (
            updateServiceStatus (
              _serviceCurStatus,
              ERROR_SERVICE_SPECIFIC_ERROR,
              -1,
              CHECKPOINT_NO_ONGOING_OPERATION,
              TIMEOUT_NONE,
              _serviceStatusHandle);
          reportLogEvent(
            reportLogEvent(
              EVENTLOG_ERROR_TYPE,
              WIN_EVENT_ID_SERVER_STOPPED_OUTSIDE_SCM,
              argCount, argc);
           }
          break;
        }
      }
@@ -1272,7 +1327,7 @@
      {
        WORD argCount = 1;
        const char *argc[] = {_instanceDir};
        debug("serviceHandler: The server could not be stopped.");
    debug("serviceHandler: The server could not be stopped.");
        // We could not stop the server
        reportLogEvent(
        EVENTLOG_ERROR_TYPE,
@@ -1374,7 +1429,7 @@
  if (myService == NULL)
  {
      debugError("getBinaryPathName: Failed to open the service '%s'.", serviceName);
    debugError("getBinaryPathName: Failed to open the service '%s'.", serviceName);
  }
  else
  {
@@ -1423,8 +1478,8 @@
    }
    if (!CloseServiceHandle(myService))
    {
      debug("getBinaryPathName: error closing handle of service. Code [%d]",
            GetLastError());
    debug("getBinaryPathName: error closing handle of service. Code [%d]",
          GetLastError());
    }
  }
@@ -2237,7 +2292,7 @@
      WIN_EVENT_ID_SERVER_START_FAILED,
      argCount, argc
      );
      debugError("startService: For instance dir '%s', %s", argc[0], argc[1]);
    debugError("startService: For instance dir '%s', %s", argc[0], argc[1]);
    }
    deregisterEventLog();
  }
opends/src/build-tools/windows/service.h
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS.
 */
#include "common.h"
@@ -106,4 +107,5 @@
   SERVICE_STATUS_HANDLE *serviceStatusHandle
   );
void serviceHandler(DWORD controlCode);
BOOL getServiceStatus(char *serviceName, LPDWORD returnState);
opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
@@ -23,7 +23,7 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2011 ForgeRock AS
 *      Portions Copyright 2011-2013 ForgeRock AS
 */
package org.opends.server.tools;
@@ -686,6 +686,7 @@
      returnValue = SERVICE_CLEANUP_ERROR;
      msg = ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName);
      err.println(msg);
      err.println("Exception:" + t.toString());
    }
    return returnValue;
  }
@@ -763,10 +764,10 @@
        break;
      case 2:
        returnValue = SERVICE_STATE_ERROR;
        if (out != null)
        if (err != null)
        {
          msg = ERR_WINDOWS_SERVICE_STATE_ERROR.get();
          out.println(msg);
          err.println(msg);
        }
        break;
      default:
@@ -784,7 +785,8 @@
      if (err != null)
      {
        msg = ERR_WINDOWS_SERVICE_STATE_ERROR.get();
        err.println(wrapText(msg, MAX_LINE_WIDTH));
        err.println(msg);
        err.println(wrapText(t.toString(), MAX_LINE_WIDTH));
      }
    }
    return returnValue;
@@ -806,8 +808,7 @@
       * Do a best effort to avoid having a relative representation (for
       * instance to avoid having ../../../).
       */
      File canonical = f.getCanonicalFile();
      f = canonical;
      f = f.getCanonicalFile();
    }
    catch (IOException ioe)
    {
opends/src/server/org/opends/server/tools/StartWindowsService.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2013 ForgeRock AS.
 */
package org.opends.server.tools;
@@ -151,7 +152,8 @@
      {
        Message message = ERR_WINDOWS_SERVICE_START_ERROR.get();
        out.println(message);
        err.println(message);
        err.println("Exception:" + t.toString());
        returnValue = SERVICE_START_ERROR;
      }
    }
opends/src/server/org/opends/server/tools/StopWindowsService.java
@@ -23,7 +23,7 @@
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2012 ForgeRock AS
 *      Portions Copyright 2012-2013 ForgeRock AS
 */
package org.opends.server.tools;
@@ -55,10 +55,6 @@
    */
  public static final int SERVICE_NOT_FOUND = 1;
  /**
    * The service was already stopped.
    */
  public static final int SERVICE_ALREADY_STOPPED = 2;
  /**
    * The service could not be stopped.
    */
  public static final int SERVICE_STOP_ERROR = 3;
@@ -79,9 +75,8 @@
   * Invokes the net stop on the service corresponding to this server, it writes
   * information and error messages in the provided streams.
   * @return <CODE>SERVICE_STOP_SUCCESSFUL</CODE>,
   * <CODE>SERVICE_NOT_FOUND</CODE>, <CODE>SERVICE_ALREADY_STOPPED</CODE> or
   * <CODE>SERVICE_STOP_ERROR</CODE> depending on whether the service could be
   * stopped or not.
   * <CODE>SERVICE_NOT_FOUND</CODE> or <CODE>SERVICE_STOP_ERROR</CODE>
   * depending on whether the service could be stopped or not.
   * @param  outStream  The stream to write standard output messages.
   * @param  errStream  The stream to write error messages.
   */
@@ -143,7 +138,12 @@
      /* Check if is a running service */
      try
      {
        if (Runtime.getRuntime().exec(cmd).waitFor() == 0)
        int resultCode = Runtime.getRuntime().exec(cmd).waitFor();
        if (resultCode == 0)
        {
          returnValue = SERVICE_STOP_SUCCESSFUL;
        }
        else if (resultCode == 2)
        {
          returnValue = SERVICE_STOP_SUCCESSFUL;
        }
@@ -156,7 +156,8 @@
      {
        Message message = ERR_WINDOWS_SERVICE_STOP_ERROR.get();
        out.println(message);
        err.println(message);
        err.println("Exception:" + t.toString());
        returnValue = SERVICE_STOP_ERROR;
      }
    }