URI:
       tservice.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       tservice.c (9633B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    Win32 Service support
            9    $Id: service.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include <windows.h>
           13 #include <stdio.h>
           14 #include <direct.h>
           15 #include <io.h>
           16 #include <fcntl.h>
           17 
           18 #include "mix3.h"
           19 
           20 #ifdef WIN32SERVICE
           21 
           22 #define SVCNAME        "Mixmaster"
           23 #define SVCDISPLAYNAME "Mixmaster Service"
           24 
           25 
           26 /* internal variables */
           27 static SERVICE_STATUS           ssStatus;
           28 static SERVICE_STATUS_HANDLE    sshStatusHandle;
           29 static BOOL                     not_service = FALSE;
           30 
           31 static HANDLE hThread = NULL;
           32 static HANDLE hMustTerminate = NULL;
           33 
           34 /* internal function prototypes */
           35 VOID WINAPI service_ctrl(DWORD ctrl_code);
           36 VOID WINAPI service_main(DWORD argc, LPSTR *argv);
           37 static DWORD service_run(void);
           38 static void service_stop();
           39 static int set_stdfiles();
           40 static int install_service();
           41 static int remove_service();
           42 static int run_notservice(int argc, char **argv);
           43 BOOL WINAPI console_ctrl_handler(DWORD ctrl_type);
           44 static char *GetLastErrorText();
           45 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id);
           46 static void event_log(DWORD id, char *eventmsg);
           47 
           48 int mix_main(int argc, char *argv[]);
           49 
           50 
           51 int main(int argc, char *argv[])
           52 {
           53     SERVICE_TABLE_ENTRY dispatchTable[] = {
           54         {SVCNAME, (LPSERVICE_MAIN_FUNCTION)service_main},
           55         {NULL,    NULL} };
           56 
           57     if ((argc > 1) && ((argv[1][0] == '-') && (argv[1][1] == '-'))) {
           58         if (!_stricmp("install-svc", argv[1]+2))
           59             return install_service();
           60         else if (!_stricmp("remove-svc", argv[1]+2))
           61             return remove_service();
           62         else if (_stricmp("run-svc", argv[1]+2) && !is_nt_service())
           63             return run_notservice(argc, argv);
           64     } else if (!is_nt_service()) {
           65         return run_notservice(argc, argv);
           66     }
           67     printf("mix --install-svc   install the service\n");
           68     printf("mix --remove-svc    remove the service\n");
           69     printf("mix --run-svc       run as a service\n");
           70     printf("mix -h          view a summary of the command line options.\n");
           71 
           72     printf("\nStartServiceCtrlDispatcher being called.\n" );
           73     printf("This may take several seconds.  Please wait.\n" );
           74     if (!StartServiceCtrlDispatcher(dispatchTable)) {
           75         printf("Service not started: StartServiceCtrlDispatcher failed.\n" );
           76         event_log(1000, "Service not started: StartServiceCtrlDispatcher failed");
           77     }
           78     return 0;
           79 } /* main */
           80 
           81 
           82 VOID WINAPI service_main(DWORD argc, LPSTR *argv)
           83 {
           84     DWORD err = 0;
           85 
           86     if (!(sshStatusHandle = RegisterServiceCtrlHandler(SVCNAME, service_ctrl)))
           87         return;
           88 
           89     ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
           90     ssStatus.dwServiceSpecificExitCode = 0;
           91     if (send_status(SERVICE_START_PENDING, NO_ERROR, 1000, 1020))
           92         err = service_run();
           93 
           94     send_status(SERVICE_STOPPED, err, 0, err ? 1030 : 30);
           95 } /* service_main */
           96 
           97 
           98 VOID WINAPI service_ctrl(DWORD ctrl_code)
           99 {   /* Handle the requested control code. */
          100     if (ctrl_code == SERVICE_CONTROL_STOP || ctrl_code == SERVICE_CONTROL_SHUTDOWN)
          101         service_stop();
          102     else
          103         send_status(ssStatus.dwCurrentState, NO_ERROR, 0, 1040 + ctrl_code);
          104 } /* service_ctrl */
          105 
          106 
          107 static DWORD service_run(void)
          108 {
          109     char filename[_MAX_PATH+1];
          110     char home[_MAX_PATH+1], *p;
          111     char *svc_argv[2] = {filename, "-D"};
          112 
          113     if (!hMustTerminate)
          114         hMustTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
          115     set_nt_exit_event(hMustTerminate);
          116     DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
          117             &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
          118 
          119     GetModuleFileName(NULL , filename, _MAX_PATH);
          120     strcpy(home, filename);
          121     if (p = strrchr(home, '\\')) {
          122         *p = 0;
          123         chdir(home);
          124     }
          125 
          126     if (!set_stdfiles()) {
          127         event_log(1010, "stdin|stdout|stderr not created");
          128         return ERROR_SERVICE_NOT_ACTIVE;
          129     }
          130 
          131     send_status(SERVICE_RUNNING, NO_ERROR, 0, 1060);
          132     event_log(10, "Mixmaster Service started");
          133 
          134     mix_main(2, svc_argv);
          135     return 0;
          136 } /* service_run */
          137 
          138 
          139 static void service_stop(void)
          140 {
          141     send_status(SERVICE_STOP_PENDING, NO_ERROR, 5000, 1070);
          142     if (hMustTerminate) {
          143         SetEvent(hMustTerminate);
          144         if (WaitForSingleObject(hThread, 4500) == WAIT_TIMEOUT) {
          145             if (hThread) {
          146                 TerminateThread(hThread, 0);
          147                 event_log(1080, "Mixmaster Service terminated forcibly");
          148             }
          149         } else
          150             event_log(20, "Mixmaster Service stopped");
          151         CloseHandle(hMustTerminate);
          152         hMustTerminate = NULL;
          153     } else
          154         if (hThread)
          155             TerminateThread(hThread, 0);
          156     if (hThread)
          157         CloseHandle(hThread);
          158     hThread = NULL;
          159     ssStatus.dwCurrentState = SERVICE_STOPPED;
          160 } /* service_stop */
          161 
          162 
          163 static int set_stdfiles()
          164 { /* needed for _popen() */
          165     static DWORD std_handles[]={STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
          166     FILE *stdfile[]={stdin, stdout, stderr};
          167     HANDLE hStd;
          168     int fh, stf_fileno;
          169     FILE *fl;
          170 
          171     AllocConsole();
          172     for (stf_fileno=0; stf_fileno<=2; stf_fileno++) {
          173         hStd = GetStdHandle(std_handles[stf_fileno]);
          174         if (hStd == INVALID_HANDLE_VALUE)
          175             return 0;
          176         fh = _open_osfhandle((long)std_handles[stf_fileno], (stf_fileno ? _O_WRONLY : _O_RDONLY ) | _O_BINARY);
          177         dup2(fh, stf_fileno);
          178         fl = _fdopen(stf_fileno, (stf_fileno ? "wcb" : "rcb" ));
          179         fflush(stdfile[stf_fileno]);
          180         memcpy(stdfile[stf_fileno], fl, sizeof(FILE));
          181     }
          182     return 1;
          183 } /* set_stdfiles */
          184 
          185 
          186 static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id)
          187 {
          188     static DWORD dwCheckPoint = 1;
          189     BOOL ret_val;
          190 
          191     if (not_service)
          192         return TRUE;
          193 
          194     ssStatus.dwCurrentState = current_state;
          195     ssStatus.dwWin32ExitCode = exit_code;
          196     ssStatus.dwWaitHint = wait_hint;
          197     ssStatus.dwControlsAccepted = (current_state == SERVICE_START_PENDING) ?
          198         0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
          199     ssStatus.dwCheckPoint = ((current_state == SERVICE_RUNNING) || (current_state == SERVICE_STOPPED)) ?
          200         0 : dwCheckPoint++;
          201 
          202     if (!(ret_val = SetServiceStatus(sshStatusHandle, &ssStatus)))
          203         event_log(id, "SetServiceStatus failed");
          204     return ret_val;
          205 } /* send_status */
          206 
          207 
          208 static void event_log(DWORD id, char *eventmsg)
          209 {
          210     HANDLE  hEventSource;
          211     char    *pStrings[2] = {"", eventmsg};
          212 
          213     if (not_service)
          214         return;
          215 
          216     if (id > 1000)
          217         pStrings[0] = GetLastErrorText();
          218 
          219     if (!(hEventSource = RegisterEventSource(NULL, SVCNAME)))
          220         return;
          221     ReportEvent(hEventSource, (WORD)((id < 1000) ? EVENTLOG_SUCCESS : EVENTLOG_ERROR_TYPE),
          222         0, id, NULL, 2, 0, pStrings, NULL);
          223     DeregisterEventSource(hEventSource);
          224 } /* event_log */
          225 
          226 
          227 static int run_notservice(int argc, char ** argv)
          228 {
          229     not_service = TRUE;
          230     return mix_main(argc, argv);
          231 } /* run_notservice */
          232 
          233 
          234 static int install_service()
          235 {
          236     SC_HANDLE schService, schSCManager;
          237     char filename[_MAX_PATH+10];
          238 
          239     if (GetModuleFileName(NULL, filename, _MAX_PATH) == 0) {
          240         printf("Unable to install Mixmaster Service: %s\n", GetLastErrorText());
          241         return 1;
          242     }
          243     strcat(filename, " --run-svc");
          244 
          245     if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
          246         printf("OpenSCManager failed: %s\n", GetLastErrorText());
          247         return 1;
          248     }
          249     schService = CreateService(schSCManager, SVCNAME, SVCDISPLAYNAME,
          250         SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
          251         filename, NULL, NULL, NULL, NULL, NULL);
          252 
          253     if (schService) {
          254         printf("Mixmaster Service installed.\n");
          255         CloseServiceHandle(schService);
          256     } else {
          257         printf("CreateService failed: %s\n", GetLastErrorText());
          258     }
          259 
          260     CloseServiceHandle(schSCManager);
          261     return 0;
          262 } /* install_service */
          263 
          264 
          265 static int remove_service()
          266 {
          267     SC_HANDLE schService, schSCManager;
          268     int ret_val = 0;
          269 
          270     if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
          271         printf("OpenSCManager failed: %s\n", GetLastErrorText());
          272         return 1;
          273     }
          274     if (!(schService = OpenService(schSCManager, SVCNAME, SERVICE_ALL_ACCESS))) {
          275         CloseServiceHandle(schSCManager);
          276         printf("OpenService failed: %s\n", GetLastErrorText());
          277         return 1;
          278     }
          279     /* try to stop the service */
          280     if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) {
          281         printf("Stopping Mixmaster Service");
          282         do {
          283             sleep(1);
          284             printf(".");
          285             QueryServiceStatus(schService, &ssStatus);
          286         } while (ssStatus.dwCurrentState != SERVICE_STOP_PENDING);
          287 
          288         if (ssStatus.dwCurrentState == SERVICE_STOPPED)
          289             printf("\nMixmaster Service stopped.\n");
          290         else
          291             printf("\n%Mixmaster Service failed to stop.\n");
          292     }
          293 
          294     /* now remove the service */
          295     if (!DeleteService(schService)) {
          296         ret_val = 1;
          297         printf("DeleteService failed: %s\n", GetLastErrorText());
          298     } else
          299         printf("Mixmaster Service removed.\n");
          300 
          301     CloseServiceHandle(schService);
          302     CloseServiceHandle(schSCManager);
          303     return ret_val;
          304 } /* remove_service */
          305 
          306 
          307 static char *GetLastErrorText()
          308 {
          309     static char error_buf[256];
          310     DWORD dwRet, err;
          311     LPSTR lpszTemp = NULL;
          312 
          313     dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
          314                           NULL, err=GetLastError(), LANG_NEUTRAL, (LPSTR)&lpszTemp, 0, NULL);
          315 
          316     /* supplied buffer is not long enough */
          317     if (!dwRet || (256 < (long)dwRet+14))
          318         sprintf(error_buf, "Error (0x%x)", err);
          319     else {
          320         lpszTemp[lstrlen(lpszTemp)-2] = '\0';
          321         /* remove cr and newline character */
          322         sprintf(error_buf, "%s (0x%x)", lpszTemp, err);
          323     }
          324 
          325     if (lpszTemp)
          326         LocalFree((HLOCAL)lpszTemp);
          327 
          328     return error_buf;
          329 } /* GetLastErrorText */
          330 
          331 #endif /* WIN32SERVICE */