|  | @@ -89,6 +89,9 @@ SERVICE_STATUS service_status;
 | 
	
		
			
				|  |  |  SERVICE_STATUS_HANDLE hStatus;
 | 
	
		
			
				|  |  |  static char **backup_argv;
 | 
	
		
			
				|  |  |  static int backup_argc;
 | 
	
		
			
				|  |  | +static int nt_service_is_stopped(void);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +#define nt_service_is_stopped() (0)
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define CHECK_DESCRIPTOR_INTERVAL 60
 | 
	
	
		
			
				|  | @@ -982,14 +985,8 @@ static int do_main_loop(void) {
 | 
	
		
			
				|  |  |    second_elapsed_callback(0,0,NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (;;) {
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS_SERVICE /* Do service stuff only on windows. */
 | 
	
		
			
				|  |  | -    if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
 | 
	
		
			
				|  |  | -      service_status.dwWin32ExitCode = 0;
 | 
	
		
			
				|  |  | -      service_status.dwCurrentState = SERVICE_STOPPED;
 | 
	
		
			
				|  |  | -      SetServiceStatus(hStatus, &service_status);
 | 
	
		
			
				|  |  | +    if (nt_service_is_stopped())
 | 
	
		
			
				|  |  |        return 0;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |      /* poll until we have an event, or the second ends */
 | 
	
		
			
				|  |  |      loop_result = event_dispatch();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1234,6 +1231,7 @@ static int tor_init(int argc, char *argv[]) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* give it somewhere to log to initially */
 | 
	
		
			
				|  |  |    add_temp_log();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    log_fn(LOG_NOTICE,"Tor v%s. This is experimental software. Do not rely on it for strong anonymity.",VERSION);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (network_init()<0) {
 | 
	
	
		
			
				|  | @@ -1324,6 +1322,22 @@ static void do_hash_password(void)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #ifdef MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | +/** If we're compile to run as an NT service, and the service has been
 | 
	
		
			
				|  |  | + * shut down, then change our current status and return 1.  Else 
 | 
	
		
			
				|  |  | + * return 0.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +nt_service_is_stopped(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
 | 
	
		
			
				|  |  | +    service_status.dwWin32ExitCode = 0;
 | 
	
		
			
				|  |  | +    service_status.dwCurrentState = SERVICE_STOPPED;
 | 
	
		
			
				|  |  | +    SetServiceStatus(hStatus, &service_status);
 | 
	
		
			
				|  |  | +    return 1;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void nt_service_control(DWORD request)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    switch (request) {
 | 
	
	
		
			
				|  | @@ -1339,7 +1353,6 @@ void nt_service_control(DWORD request)
 | 
	
		
			
				|  |  |  void nt_service_body(int argc, char **argv)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    int err;
 | 
	
		
			
				|  |  | -  FILE *f;
 | 
	
		
			
				|  |  |    service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
 | 
	
		
			
				|  |  |    service_status.dwCurrentState = SERVICE_START_PENDING;
 | 
	
		
			
				|  |  |    service_status.dwControlsAccepted =
 | 
	
	
		
			
				|  | @@ -1349,10 +1362,12 @@ void nt_service_body(int argc, char **argv)
 | 
	
		
			
				|  |  |    service_status.dwCheckPoint = 0;
 | 
	
		
			
				|  |  |    service_status.dwWaitHint = 1000;
 | 
	
		
			
				|  |  |    hStatus = RegisterServiceCtrlHandler(GENSRV_SERVICENAME, (LPHANDLER_FUNCTION) nt_service_control);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (hStatus == 0) {
 | 
	
		
			
				|  |  |      // failed;
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    err = tor_init(backup_argc, backup_argv); // refactor this part out of tor_main and do_main_loop
 | 
	
		
			
				|  |  |    if (err) {
 | 
	
		
			
				|  |  |      // failed.
 | 
	
	
		
			
				|  | @@ -1376,6 +1391,7 @@ void nt_service_main(void)
 | 
	
		
			
				|  |  |    table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
 | 
	
		
			
				|  |  |    table[1].lpServiceName = NULL;
 | 
	
		
			
				|  |  |    table[1].lpServiceProc = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (!StartServiceCtrlDispatcher(table)) {
 | 
	
		
			
				|  |  |      result = GetLastError();
 | 
	
		
			
				|  |  |      printf("Error was %d\n",result);
 | 
	
	
		
			
				|  | @@ -1404,11 +1420,15 @@ int nt_service_install()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    /* XXXX Problems with NT services:
 | 
	
		
			
				|  |  |     * 1. The configuration file needs to be in the same directory as the .exe
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  |     * 2. The exe and the configuration file can't be on any directory path
 | 
	
		
			
				|  |  |     *    that contains a space.
 | 
	
		
			
				|  |  | +   *    mje - you can quote the string (i.e., "c:\program files")
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  |     * 3. Ideally, there should be one EXE that can either run as a
 | 
	
		
			
				|  |  |     *    separate process (as now) or that can install and run itself
 | 
	
		
			
				|  |  |     *    as an NT service.  I have no idea how hard this is.
 | 
	
		
			
				|  |  | +   *    mje - should be done. It can install and run itself as a service
 | 
	
		
			
				|  |  |     *
 | 
	
		
			
				|  |  |     * Notes about developing NT services:
 | 
	
		
			
				|  |  |     *
 | 
	
	
		
			
				|  | @@ -1432,14 +1452,21 @@ int nt_service_install()
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    _tsplitpath(szPath, szDrive, szDir, NULL, NULL);
 | 
	
		
			
				|  |  | -  len = _MAX_PATH + strlen(cmd1) + _MAX_DRIVE + _MAX_DIR + strlen(cmd2);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* Account for the extra quotes */
 | 
	
		
			
				|  |  | +  //len = _MAX_PATH + strlen(cmd1) + _MAX_DRIVE + _MAX_DIR + strlen(cmd2);
 | 
	
		
			
				|  |  | +  len = _MAX_PATH + strlen(cmd1) + _MAX_DRIVE + _MAX_DIR + strlen(cmd2) + 4;
 | 
	
		
			
				|  |  |    command = tor_malloc(len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  strlcpy(command, szPath, len);
 | 
	
		
			
				|  |  | -  strlcat(command, " -f ", len);
 | 
	
		
			
				|  |  | -  strlcat(command, szDrive, len);
 | 
	
		
			
				|  |  | -  strlcat(command, szDir, len);
 | 
	
		
			
				|  |  | -  strlcat(command, "\\torrc", len);
 | 
	
		
			
				|  |  | +  /* Create a quoted command line, like "c:\with spaces\tor.exe" -f
 | 
	
		
			
				|  |  | +   * "c:\with spaces\tor.exe"
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  if (tor_snprintf(command, len, "\"%s\" -f \"%s%storrc\"",
 | 
	
		
			
				|  |  | +                   szPath,  szDrive, szDir)<0) {
 | 
	
		
			
				|  |  | +    printf("Failed: tor_snprinf()\n");
 | 
	
		
			
				|  |  | +    free(command);
 | 
	
		
			
				|  |  | +    return 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if ((hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
 | 
	
		
			
				|  |  |      printf("Failed: OpenSCManager()\n");
 | 
	
	
		
			
				|  | @@ -1447,21 +1474,31 @@ int nt_service_install()
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* 1/26/2005 mje
 | 
	
		
			
				|  |  | +   * - changed the service start type to auto
 | 
	
		
			
				|  |  | +   * - and changed the lpPassword param to "" instead of NULL as per an
 | 
	
		
			
				|  |  | +   *   MSDN article.
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  |    if ((hService = CreateService(hSCManager, GENSRV_SERVICENAME, GENSRV_DISPLAYNAME,
 | 
	
		
			
				|  |  |                                  SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
 | 
	
		
			
				|  |  | -                                SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, command,
 | 
	
		
			
				|  |  | -                                NULL, NULL, NULL, NULL, NULL)) == NULL) {
 | 
	
		
			
				|  |  | +                                SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, command,
 | 
	
		
			
				|  |  | +                                NULL, NULL, NULL, NULL, "")) == NULL) {
 | 
	
		
			
				|  |  |      printf("Failed: CreateService()\n");
 | 
	
		
			
				|  |  |      CloseServiceHandle(hSCManager);
 | 
	
		
			
				|  |  |      free(command);
 | 
	
		
			
				|  |  |      return 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* Start the service initially, so you don't have to muck with it in the SCM
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  if(!StartService(hService, 0, NULL))
 | 
	
		
			
				|  |  | +    printf("Service installed, but not started.\n");
 | 
	
		
			
				|  |  | +  else
 | 
	
		
			
				|  |  | +    printf("Service installed and started successfully!\n");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    CloseServiceHandle(hService);
 | 
	
		
			
				|  |  |    CloseServiceHandle(hSCManager);
 | 
	
		
			
				|  |  | -  free(command);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  printf("Install service successfully\n");
 | 
	
		
			
				|  |  | +  tor_free(command);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 |