forum.vdsworld.com Forum Index forum.vdsworld.com
Visit VDSWORLD.com
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


ServiceCTL - A modified version of XYNTService

 
Post new topic   Reply to topic    forum.vdsworld.com Forum Index -> Advanced VDS 5 Source Code
View previous topic :: View next topic  
Author Message
henrywood
Contributor
Contributor


Joined: 21 Sep 2004
Posts: 66
Location: Copenhagen, Denmark

PostPosted: Sun Aug 28, 2005 8:57 pm    Post subject: ServiceCTL - A modified version of XYNTService Reply with quote

Hi guys !

Since I have experienced that the XYNTService on VDS World does not guarantee proper service shutdown and restart,
I have modified it.

This will enable your VDS based service to properly release resources before stopping/restarting.

Please see the documentation for XYNTService in CodeScript's VDS Service Example found elsewhere on VDSWORLD

C++ code follows: (A compiled version is here: http://www.vdsworld.com/download.php?id=474)

Code:

///////////////////////////////////////////////////////////////////////
//
// servicectl.cpp
//
///////////////////////////////////////////////////////////////////////
//
// A modified version of XYNTService to provide VDS based services
// the possibility to do a clean shutdown and restart
//
///////////////////////////////////////////////////////////////////////
//
// Modified by Henrik Skov (henrywood@webspeed.dk)
//
///////////////////////////////////////////////////////////////////////
//
// The VDS service part must handle windows custom message event 12287
//($2FFF) like so:
//
// OPTION MSGEVENT,$2FFF,SHUTDOWN,HANDLED
//
// # Catch windows message $2FFF
// :SHUTDOWN
// %%SERVICE_SHUTDOWN = 1
// goto close
//
// :CLOSE
// # Release resources and write any logs here
//
//
//
//# These lines signals to the servicecl.exe that shutdown is complete
// if %%SERVICE_SHUTDOWN
//   inifile open,@path(%0)servicectl.ini
//   inifile write,Process0,ShutdownWait,N
//   repeat
//     %E = @event()
//   until @equal(%E,CLOSE)
// 
// end
// stop
//
//
//
//////////////////////////////////////////////////////////////////////
// NT Service Stub Code (For XYROOT )
//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <winsvc.h>
#include <process.h>


const int nBufferSize = 500;
char pServiceName[nBufferSize+1];
char pExeFile[nBufferSize+1];
char pInitFile[nBufferSize+1];
char pLogFile[nBufferSize+1];
int nProcCount = 0;
PROCESS_INFORMATION* pProcInfo = 0;

SERVICE_STATUS          serviceStatus;
SERVICE_STATUS_HANDLE   hServiceStatusHandle;

VOID WINAPI XYNTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
VOID WINAPI XYNTServiceHandler( DWORD fdwControl );


//////////////////////////////////////////////////////////////////////
//
// Configuration Data and Tables
//

SERVICE_TABLE_ENTRY   DispatchTable[] =
{
   {pServiceName, XYNTServiceMain},
   {NULL, NULL}
};


// helper functions

BOOL StartProcess(int nIndex)
{
   STARTUPINFO startUpInfo = { sizeof(STARTUPINFO),NULL,"",NULL,0,0,0,0,0,0,0,0,SW_HIDE,0,NULL,0,0,0}; 
   
   char pItem[nBufferSize+1];
   sprintf(pItem,"Process%d\0",nIndex);
   char pCommandLine[nBufferSize+1];
   GetPrivateProfileString(pItem,"CommandLine","",pCommandLine,nBufferSize,pInitFile);
   char pUserInterface[nBufferSize+1];
   GetPrivateProfileString(pItem,"UserInterface","N",pUserInterface,nBufferSize,pInitFile);
   BOOL bUserInterface = (pUserInterface[0]=='y'||pUserInterface[0]=='Y'||pUserInterface[0]=='1')?TRUE:FALSE;
   if(bUserInterface)
   {
      startUpInfo.wShowWindow = SW_SHOW;
      startUpInfo.lpDesktop = NULL;
   }
   char pWorkingDir[nBufferSize+1];
   GetPrivateProfileString(pItem,"WorkingDir","",pWorkingDir,nBufferSize,pInitFile);
   if(CreateProcess(NULL,pCommandLine,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,strlen(pWorkingDir)==0?NULL:pWorkingDir,&startUpInfo,&pProcInfo[nIndex]))
   {
      char pPause[nBufferSize+1];
      GetPrivateProfileString(pItem,"PauseStart","100",pPause,nBufferSize,pInitFile);
      Sleep(atoi(pPause));
      return TRUE;
   }
   else
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog,"Failed to start program '%s', error code = %d\n", pCommandLine, nError);
      fclose(pLog);
      return FALSE;
   }
}

void EndProcess(int nIndex)
{   
    // HS Added
    BOOL bCompleted = FALSE;
           
   char pItem[nBufferSize+1];
   sprintf(pItem,"Process%d\0",nIndex);
   char pPause[nBufferSize+1];
   GetPrivateProfileString(pItem,"PauseEnd","100",pPause,nBufferSize,pInitFile);
   int nPauseEnd = atoi(pPause);
   if(nIndex>=0&&nIndex<nProcCount)
   {
      if(pProcInfo[nIndex].hProcess)
      {
         if(nPauseEnd>0)
         {
            
            //PostThreadMessage(pProcInfo[nIndex].dwThreadId,WM_QUIT,0,0);¨
            // FIXED BY HS...
            
            // Send SHUTDOWN message to VDS EXE
            PostThreadMessage(pProcInfo[nIndex].dwThreadId,12287,0,0);
            // Give VDS EXE time to process the message
            Sleep(nPauseEnd);
            
                // Wait for the shutdown to complete
                // It is complete when the value of key 'Shutdown' is "N" in section Process[nIndex]
                // In other words, the VDS EXE must load the servicectl.ini and set that value to 'N' to
                // signal completion of shutdown
                //
                // This is a workaround for the fact the VDS cannot respond to the custom message sent
                // to it...
            
            // Write to ini file
            WritePrivateProfileString(pItem,"ShutdownWait","Y",pInitFile);

            char pShutdown[nBufferSize+1];
             
                do {
               
                     GetPrivateProfileString(pItem,"ShutdownWait","Y",pShutdown,nBufferSize,pInitFile);
                    bCompleted = (pShutdown[0]=='n' || pShutdown[0] =='N') ? TRUE : FALSE;
                                
                } while ( ! bCompleted );
            
            // and send WM_QUIT -> will regenerate a CLOSE event in VDS EXE )
            // This may not be needed !!!
            PostThreadMessage(pProcInfo[nIndex].dwThreadId,WM_QUIT,0,0);
            Sleep(nPauseEnd);

         }
         TerminateProcess(pProcInfo[nIndex].hProcess,0);
      }
   }
}

BOOL BounceProcess(char* pName, int nIndex)
{
   SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
   if (schSCManager==0)
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog, "OpenSCManager failed, error code = %d\n", nError);
      fclose(pLog);
   }
   else
   {
      SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
      if (schService==0)
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "OpenService failed, error code = %d\n", nError);
         fclose(pLog);
      }
      else
      {
         SERVICE_STATUS status;
         if(nIndex>=0&&nIndex<128)
         {
            if(ControlService(schService,(nIndex|0x80),&status))
            {
               CloseServiceHandle(schService);
               CloseServiceHandle(schSCManager);
               return TRUE;
            }
            long nError = GetLastError();
            FILE* pLog = fopen(pLogFile,"a");
            fprintf(pLog, "ControlService failed, error code = %d\n", nError);
            fclose(pLog);
         }
         else
         {
            FILE* pLog = fopen(pLogFile,"a");
            fprintf(pLog, "Invalid argument to BounceProcess: %d\n", nIndex);
            fclose(pLog);
         }
         CloseServiceHandle(schService);
      }
      CloseServiceHandle(schSCManager);
   }
   return FALSE;
}

BOOL KillService(char* pName)
{
   SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
   if (schSCManager==0)
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog, "OpenSCManager failed, error code = %d\n", nError);
      fclose(pLog);
   }
   else
   {
      SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
      if (schService==0)
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "OpenService failed, error code = %d\n", nError);
         fclose(pLog);
      }
      else
      {
         SERVICE_STATUS status;
         if(ControlService(schService,SERVICE_CONTROL_STOP,&status))
         {
            CloseServiceHandle(schService);
            CloseServiceHandle(schSCManager);
            return TRUE;
         }
         else
         {
            long nError = GetLastError();
            FILE* pLog = fopen(pLogFile,"a");
            fprintf(pLog, "ControlService failed, error code = %d\n", nError);
            fclose(pLog);
         }
         CloseServiceHandle(schService);
      }
      CloseServiceHandle(schSCManager);
   }
   return FALSE;
}

BOOL RunService(char* pName, int nArg, char** pArg)
{
   SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
   if (schSCManager==0)
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog, "OpenSCManager failed, error code = %d\n", nError);
      fclose(pLog);
   }
   else
   {
      SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
      if (schService==0)
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "OpenService failed, error code = %d\n", nError);
         fclose(pLog);
      }
      else
      {
         if(StartService(schService,nArg,(const char**)pArg))
         {
            CloseServiceHandle(schService);
            CloseServiceHandle(schSCManager);
            return TRUE;
         }
         else
         {
            long nError = GetLastError();
            FILE* pLog = fopen(pLogFile,"a");
            fprintf(pLog, "StartService failed, error code = %d\n", nError);
            fclose(pLog);
         }
         CloseServiceHandle(schService);
      }
      CloseServiceHandle(schSCManager);
   }
   return FALSE;
}

//////////////////////////////////////////////////////////////////////
//
// This routine gets used to start your service
//
VOID WINAPI XYNTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
   DWORD   status = 0;
    DWORD   specificError = 0xfffffff;
 
    serviceStatus.dwServiceType        = SERVICE_WIN32;
    serviceStatus.dwCurrentState       = SERVICE_START_PENDING;
    serviceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
    serviceStatus.dwWin32ExitCode      = 0;
    serviceStatus.dwServiceSpecificExitCode = 0;
    serviceStatus.dwCheckPoint         = 0;
    serviceStatus.dwWaitHint           = 0;
 
    hServiceStatusHandle = RegisterServiceCtrlHandler(pServiceName, XYNTServiceHandler);
    if (hServiceStatusHandle==0)
    {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
        fprintf(pLog, "RegisterServiceCtrlHandler failed, error code = %d\n", nError);
      fclose(pLog);
        return;
    }
 
    // Handle error condition
   status = GetLastError();
    if (status!=NO_ERROR)
   {
        serviceStatus.dwCurrentState       = SERVICE_STOPPED;
        serviceStatus.dwCheckPoint         = 0;
        serviceStatus.dwWaitHint           = 0;
        serviceStatus.dwWin32ExitCode      = status;
        serviceStatus.dwServiceSpecificExitCode = specificError;
        SetServiceStatus(hServiceStatusHandle, &serviceStatus);
        return;
    }
 
    // Initialization complete - report running status
    serviceStatus.dwCurrentState       = SERVICE_RUNNING;
    serviceStatus.dwCheckPoint         = 0;
    serviceStatus.dwWaitHint           = 0; 
    if(!SetServiceStatus(hServiceStatusHandle, &serviceStatus))
    {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
        fprintf(pLog, "SetServiceStatus failed, error code = %d\n", nError);
      fclose(pLog);
    }

   for(int i=0;i<nProcCount;i++)
   {
      pProcInfo[i].hProcess = 0;
      StartProcess(i);
   }
}

//////////////////////////////////////////////////////////////////////
//
// This routine responds to events concerning your service, like start/stop
//
VOID WINAPI XYNTServiceHandler(DWORD fdwControl)
{
     //int i = 0;
     
   switch(fdwControl)
   {
      case SERVICE_CONTROL_STOP:
      case SERVICE_CONTROL_SHUTDOWN:
         serviceStatus.dwWin32ExitCode = 0;
         serviceStatus.dwCurrentState  = SERVICE_STOPPED;
         serviceStatus.dwCheckPoint    = 0;
         serviceStatus.dwWaitHint      = 0;
         {
            for(int i=nProcCount-1;i>=0;i--)
            {
               EndProcess(i);
            }         
            if (!SetServiceStatus(hServiceStatusHandle, &serviceStatus))
            {
               long nError = GetLastError();
               FILE* pLog = fopen(pLogFile,"a");
               fprintf(pLog, "SetServiceStatus failed, error code = %d\n",nError);
               fclose(pLog);
            }
         }
         return;
      case SERVICE_CONTROL_PAUSE:
         serviceStatus.dwCurrentState = SERVICE_PAUSED;
         break;
      case SERVICE_CONTROL_CONTINUE:
         serviceStatus.dwCurrentState = SERVICE_RUNNING;
         break;
      case SERVICE_CONTROL_INTERROGATE:
         break;
      default:
         if(fdwControl>=128&&fdwControl<256)
         {
            int nIndex = fdwControl&0x7F;
            if(nIndex>=0&&nIndex<nProcCount)
            {
               EndProcess(nIndex);
               StartProcess(nIndex);
            }
            else if(nIndex==127)
            {
               for(int i=nProcCount-1;i>=0;i--)
               {
                  EndProcess(i);
               }
               for(int j=0;j<nProcCount;j++)
               {
                  StartProcess(j);
               }
            }
         }
         else
         {
            FILE* pLog = fopen(pLogFile,"a");
            fprintf(pLog, "Unrecognized opcode %d\n", fdwControl);
            fclose(pLog);
         }
   };
    if (!SetServiceStatus(hServiceStatusHandle,  &serviceStatus))
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
        fprintf(pLog, "SetServiceStatus failed, error code = %d\n",nError);
      fclose(pLog);
    }
}


//////////////////////////////////////////////////////////////////////
//
// Uninstall
//
VOID UnInstall(char* pName)
{
   SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
   if (schSCManager==0)
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog, "OpenSCManager failed, error code = %d\n", nError);
      fclose(pLog);
   }
   else
   {
      SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS);
      if (schService==0)
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "OpenService failed, error code = %d\n",nError);
         fclose(pLog);
      }
      else
      {
         FILE* pLog = fopen(pLogFile,"a");
         if(!DeleteService(schService)) fprintf(pLog, "Failed to delete service %s\n", pName);
         else fprintf(pLog, "Service %s removed\n",pName);
         fclose(pLog);
         CloseServiceHandle(schService);
      }
      CloseServiceHandle(schSCManager);   
   }
}

//////////////////////////////////////////////////////////////////////
//
// Install
//
VOID Install(char* pPath, char* pName)

   SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
   if (schSCManager==0)
   {
      long nError = GetLastError();
      FILE* pLog = fopen(pLogFile,"a");
      fprintf(pLog, "OpenSCManager failed, error code = %d\n", nError);
      fclose(pLog);
   }
   else
   {
      SC_HANDLE schService = CreateService
      (
         schSCManager,   /* SCManager database      */
         pName,         /* name of service         */
         pName,         /* service name to display */
         SERVICE_ALL_ACCESS,        /* desired access          */
         SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS , /* service type            */
         SERVICE_AUTO_START,      /* start type              */
         SERVICE_ERROR_NORMAL,      /* error control type      */
         pPath,         /* service's binary        */
         NULL,                      /* no load ordering group  */
         NULL,                      /* no tag identifier       */
         NULL,                      /* no dependencies         */
         NULL,                      /* LocalSystem account     */
         NULL
      );                     /* no password             */
      if (schService==0)
      {
         long nError =  GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "Failed to create service %s, error code = %d\n", pName, nError);
         fclose(pLog);
      }
      else
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog, "Service %s installed\n", pName);
         fclose(pLog);
         CloseServiceHandle(schService);
      }
      CloseServiceHandle(schSCManager);
   }   
}

void WorkerProc(void* pParam)
{
   char pCheckProcess[nBufferSize+1];
   GetPrivateProfileString("Settings","CheckProcess","60",pCheckProcess, nBufferSize,pInitFile);
   int nCheckProcess = atoi(pCheckProcess);
   while(nCheckProcess>0&&nProcCount>0)
   {
      ::Sleep(1000*60*nCheckProcess);
      for(int i=0;i<nProcCount;i++)
      {
         char pItem[nBufferSize+1];
         sprintf(pItem,"Process%d\0",i);
         char pRestart[nBufferSize+1];
         GetPrivateProfileString(pItem,"Restart","No",pRestart,nBufferSize,pInitFile);
         if(pRestart[0]=='Y'||pRestart[0]=='y'||pRestart[0]=='1')
         {
            DWORD dwCode;
            if(::GetExitCodeProcess(pProcInfo[i].hProcess, &dwCode))
            {
               if(dwCode!=STILL_ACTIVE)
               {
                  if(StartProcess(i))
                  {
                     FILE* pLog = fopen(pLogFile,"a");
                     fprintf(pLog,"Restarted process %d\n", i);
                     fclose(pLog);
                  }
               }
            }
            else
            {
               long nError = GetLastError();
               FILE* pLog = fopen(pLogFile,"a");
               fprintf(pLog,"GetExitCodeProcess failed, error code = %d\n", nError);
               fclose(pLog);
            }
         }
      }
   }
}

//////////////////////////////////////////////////////////////////////
//
// Standard C Main
//
int main(int argc, char *argv[] )
{
   char pModuleFile[nBufferSize+1];
   DWORD dwSize = GetModuleFileName(NULL,pModuleFile,nBufferSize);
   pModuleFile[dwSize] = 0;
   if(dwSize>4&&pModuleFile[dwSize-4]=='.')
   {
      sprintf(pExeFile,"%s",pModuleFile);
      pModuleFile[dwSize-4] = 0;
      sprintf(pInitFile,"%s.ini",pModuleFile);
      sprintf(pLogFile,"%s.log",pModuleFile);
   }
   else
   {
      sprintf(pExeFile,"%s",argv[0]);
      sprintf(pInitFile,"%s","XYNTService.ini");
      sprintf(pLogFile,"%s","XYNTService.log");
   }

   GetPrivateProfileString("Settings","ServiceName","XYNTService",pServiceName,nBufferSize,pInitFile);
   char pCount[nBufferSize+1];
   GetPrivateProfileString("Settings","ProcCount","",pCount,nBufferSize,pInitFile);
   nProcCount = atoi(pCount);
   if(nProcCount>0)
   {
      pProcInfo = new PROCESS_INFORMATION[nProcCount];
   }
   if(argc==2&&_stricmp("-u",argv[1])==0)
   {
      UnInstall(pServiceName);
   }
   else if(argc==2&&_stricmp("-i",argv[1])==0)
   {         
      Install(pExeFile, pServiceName);
   }
   else if(argc==2&&_stricmp("-b",argv[1])==0)
   {         
      KillService(pServiceName);
      RunService(pServiceName,0,NULL);
   }
   else if(argc==3&&_stricmp("-b",argv[1])==0)
   {
      int nIndex = atoi(argv[2]);
      if(BounceProcess(pServiceName, nIndex))
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Bounced process %d.\n", nIndex);
         fclose(pLog);
      }
      else
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Failed to bounce process %d.\n", nIndex);
         fclose(pLog);
      }
   }
   else if(argc==3&&_stricmp("-k",argv[1])==0)
   {
      if(KillService(argv[2]))
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Killed service %s.\n", argv[2]);
         fclose(pLog);
      }
      else
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Failed to kill service %s.\n", argv[2]);
         fclose(pLog);
      }
   }
   else if(argc>=3&&_stricmp("-r",argv[1])==0)
   {
      if(RunService(argv[2], argc>3?(argc-3):0,argc>3?(&(argv[3])):NULL))
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Ran service %s.\n", argv[2]);
         fclose(pLog);
      }
      else
      {
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"Failed to run service %s.\n", argv[2]);
         fclose(pLog);
      }
   }
   else
   {
      if(_beginthread(WorkerProc, 0, NULL)==-1)
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"_beginthread failed, error code = %d\n", nError);
         fclose(pLog);
      }
      if(!StartServiceCtrlDispatcher(DispatchTable))
      {
         long nError = GetLastError();
         FILE* pLog = fopen(pLogFile,"a");
         fprintf(pLog,"StartServiceCtrlDispatcher failed, error code = %d\n", nError);
         fclose(pLog);
      }
   }
   delete []pProcInfo;

return 0;
}

Back to top
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   Reply to topic    forum.vdsworld.com Forum Index -> Advanced VDS 5 Source Code All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum

Twitter@vdsworld       RSS

Powered by phpBB © 2001, 2005 phpBB Group