[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r9185: Patch from Edmanm, slightly modified. Original change list: (in tor/trunk: . src/or)



Author: nickm
Date: 2006-12-24 01:32:24 -0500 (Sun, 24 Dec 2006)
New Revision: 9185

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
Log:
 r11702@Kushana:  nickm | 2006-12-24 01:31:59 -0500
 Patch from Edmanm, slightly modified.  Original change list:
   - Support running the Tor service with a torrc not in the
     same directory as tor.exe (Bug #356) and default to using the torrc
     located in the %appdata%\Tor\ of the user who installed the service
   - Removed the supposedly misleading error message mentioned in Bug #294
   - Fixed some CloseHandle()s that should've been CloseServiceHandle()s
   - Fixed some nt_service_foo() return values to be consistent
   - Resolved some nt_service_foo() DOCDOCs
   - Fixed one trivial typo that I happened to randomly notice
 
 Changes:
   - Make more comments into "imperative" house style.
   - Remove special handling for "-f"; only use --options.
   - Quote all options.
   - Clean up whitespace
 



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r11702] on c95137ef-5f19-0410-b913-86e773d04f59

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2006-12-24 06:32:20 UTC (rev 9184)
+++ tor/trunk/ChangeLog	2006-12-24 06:32:24 UTC (rev 9185)
@@ -12,6 +12,10 @@
       clients to tell which servers support BEGIN_DIR and which don't.
       The implementation is forward-compatible with a proposed future
       protocol version scheme not tied to Tor versions.
+    - Support running the Tor service with a torrc not in the
+      same directory as tor.exe (Bug #356) and default to using the torrc
+      located in the %appdata%\Tor\ of the user who installed the service.
+      Patch from Matt Edman.
 
   o Minor features:
     - Start using the state file to store bandwidth accounting data:
@@ -100,6 +104,10 @@
     - Stop accepting certain malformed ports in configured exit policies.
     - Don't re-write the fingerprint file every restart, unless it has
       changed.
+    - Cleaned-up code and documentation in NT services. Patch from Matt
+      Edman.
+    - Removed the supposedly misleading error message mentioned in Bug #294.
+      Patch from Matt Edman.
 
   o Controller features:
     - Have GETINFO dir/status/* work on hosts with DirPort disabled.

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2006-12-24 06:32:20 UTC (rev 9184)
+++ tor/trunk/src/or/main.c	2006-12-24 06:32:24 UTC (rev 9185)
@@ -78,7 +78,6 @@
 // Cheating: using the pre-defined error codes, tricks Windows into displaying
 //           a semi-related human-readable error message if startup fails as
 //           opposed to simply scaring people with Error: 0xffffffff
-#define NT_SERVICE_ERROR_NO_TORRC ERROR_FILE_NOT_FOUND
 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
 
 SERVICE_STATUS service_status;
@@ -1723,6 +1722,8 @@
                   NULL, NULL, NULL, NULL, NULL, NULL,
                   NULL, NULL, NULL, NULL, NULL, NULL };
 
+/** Loads functions used by NT services. Returns 0 on success, or -1 on
+ * error. */
 static int
 nt_service_loadlibrary(void)
 {
@@ -1767,49 +1768,6 @@
   return 0;
 }
 
-/** Checks if torrc is present in the same directory
- *  as the service executable.
- *  Return 1 if it is, 0 if it is not present. */
-static int
-nt_torrc_is_present()
-{
-  HANDLE hFile;
-  TCHAR szPath[_MAX_PATH];
-  TCHAR szDrive[_MAX_DRIVE];
-  TCHAR szDir[_MAX_DIR];
-  char torrc[] = "torrc";
-  char *path_to_torrc;
-  int len = 0;
-
-  /* Get the service executable path */
-  if (0 == GetModuleFileName(NULL, szPath, MAX_PATH))
-    return 0;
-  _tsplitpath(szPath, szDrive, szDir, NULL, NULL);
-
-  /* Build the path to the torrc file */
-  len = _MAX_PATH + _MAX_DRIVE + _MAX_DIR + strlen(torrc) + 1;
-  path_to_torrc = tor_malloc(len);
-  if (tor_snprintf(path_to_torrc, len, "%s%s%s", szDrive,  szDir, torrc)<0) {
-    printf("Failed: tor_snprinf()\n");
-    tor_free(path_to_torrc);
-    return 0;
-  }
-
-  /* See if torrc is present */
-  hFile = CreateFile(TEXT(path_to_torrc),
-                     GENERIC_READ, FILE_SHARE_READ, NULL,
-                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
-                     NULL);
-
-  tor_free(path_to_torrc);
-
-  if (hFile == INVALID_HANDLE_VALUE) {
-    return 0;
-  }
-  CloseHandle(hFile);
-  return 1;
-}
-
 /** If we're compiled to run as an NT service, and the service has been
  * shut down, then change our current status and return 1.  Else
  * return 0.
@@ -1831,7 +1789,8 @@
   return 0;
 }
 
-/** DOCDOC */
+/** Handles service control requests, such as stopping or starting the
+ * Tor service. */
 void
 nt_service_control(DWORD request)
 {
@@ -1854,7 +1813,10 @@
   service_fns.SetServiceStatus_fn(hStatus, &service_status);
 }
 
-/** DOCDOC */
+/** Called when the service is started via the system's service control
+ * manager. This calls tor_init() and starts the main event loop. If
+ * tor_init() fails, the service will be stopped and exit code set to
+ * NT_SERVICE_ERROR_TORINIT_FAILED. */
 void
 nt_service_body(int argc, char **argv)
 {
@@ -1873,40 +1835,31 @@
                                    (LPHANDLER_FUNCTION) nt_service_control);
 
   if (hStatus == 0) {
-    // failed;
+    /* Failed to register the service control handler function */
     return;
   }
 
-  // check for torrc
-  if (nt_torrc_is_present()) {
-    r = tor_init(backup_argc, backup_argv);
-    // refactor this part out of tor_main and do_main_loop
-    if (r) {
-      r = NT_SERVICE_ERROR_TORINIT_FAILED;
-    }
-  }
-  else {
-    log_err(LD_CONFIG, "torrc is not in the current working directory. "
-            "The Tor service will not start.");
-    r = NT_SERVICE_ERROR_NO_TORRC;
-  }
-
+  r = tor_init(backup_argc, backup_argv);
   if (r) {
-    // failed.
+    /* Failed to start the Tor service */
+    r = NT_SERVICE_ERROR_TORINIT_FAILED;
     service_status.dwCurrentState = SERVICE_STOPPED;
     service_status.dwWin32ExitCode = r;
     service_status.dwServiceSpecificExitCode = r;
     service_fns.SetServiceStatus_fn(hStatus, &service_status);
     return;
   }
+
+  /* Set the service's status to SERVICE_RUNNING and start the main
+   * event loop */
   service_status.dwCurrentState = SERVICE_RUNNING;
   service_fns.SetServiceStatus_fn(hStatus, &service_status);
   do_main_loop();
   tor_cleanup();
-  return;
 }
 
-/** DOCDOC */
+/** Main service entry point. Starts the service control dispatcher and waits
+ * until the service status is set to SERVICE_STOPPED. */
 void
 nt_service_main(void)
 {
@@ -1950,12 +1903,14 @@
   }
 }
 
-/** DOCDOC */
+/** Return a handle to the service control manager on success, or NULL on
+ * failure. */
 SC_HANDLE
 nt_service_open_scm(void)
 {
   SC_HANDLE hSCManager;
   char *errmsg = NULL;
+
   if (nt_service_loadlibrary()<0)
     return 0;
   if ((hSCManager = service_fns.OpenSCManagerA_fn(
@@ -1967,7 +1922,8 @@
   return hSCManager;
 }
 
-/** DOCDOC */
+/** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
+ * on failure. */
 SC_HANDLE
 nt_service_open(SC_HANDLE hSCManager)
 {
@@ -1985,7 +1941,8 @@
   return hService;
 }
 
-/** DOCDOC */
+/** Start the Tor service. Return 0 if the service is started or was
+ * previously running. Return -1 on error. */
 int
 nt_service_start(SC_HANDLE hService)
 {
@@ -1997,7 +1954,7 @@
   service_fns.QueryServiceStatus_fn(hService, &service_status);
   if (service_status.dwCurrentState == SERVICE_RUNNING) {
     printf("Service is already running\n");
-    return 1;
+    return 0;
   }
 
   if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
@@ -2010,7 +1967,7 @@
     /* Check if it started successfully or not */
     if (service_status.dwCurrentState == SERVICE_RUNNING) {
       printf("Service started successfully\n");
-      return 1;
+      return 0;
     } else {
       errmsg = nt_strerror(service_status.dwWin32ExitCode);
       printf("Service failed to start : %s\n", errmsg);
@@ -2021,10 +1978,11 @@
     printf("StartService() failed : %s\n", errmsg);
     LocalFree(errmsg);
   }
-  return 0;
+  return -1;
 }
 
-/** DOCDOC */
+/** Stop the Tor service. Return 0 if the service is stopped or was not
+ * previously running. Return -1 on error. */
 int
 nt_service_stop(SC_HANDLE hService)
 {
@@ -2038,7 +1996,7 @@
   service_fns.QueryServiceStatus_fn(hService, &service_status);
   if (service_status.dwCurrentState == SERVICE_STOPPED) {
     printf("Service is already stopped\n");
-    return 1;
+    return 0;
   }
 
   if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
@@ -2052,7 +2010,7 @@
     }
     if (service_status.dwCurrentState == SERVICE_STOPPED) {
       printf("Service stopped successfully\n");
-      return 1;
+      return 0;
     } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
       printf("Service did not stop within %d seconds.\n", wait_time);
     } else {
@@ -2060,33 +2018,72 @@
       printf("QueryServiceStatus() failed : %s\n",errmsg);
       LocalFree(errmsg);
     }
-  }
-  else {
+  } else {
     errmsg = nt_strerror(GetLastError());
     printf("ControlService() failed : %s\n", errmsg);
     LocalFree(errmsg);
   }
-  return 0;
+  return -1;
 }
 
-/** DOCDOC */
+/** Build a formatted command line used for the NT service. Return a
+ * pointer to the formatted string on success, or NULL on failure. */
+char *
+nt_service_command_line(void)
+{
+  TCHAR tor_exe[MAX_PATH+1];
+  char *command, *options;
+  const char *torrc;
+  smartlist_t *sl;
+  int i, cmdlen;
+  int use_default_torrc = 1;
+
+  /* Get the location of tor.exe */
+  if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
+    return NULL;
+
+  /* Get the service arguments */
+  sl = smartlist_create();
+  torrc = get_torrc_fname();
+  for (i = 1; i < backup_argc; ++i) {
+    if (!strcmp(backup_argv[i], "--options") ||
+        !strcmp(backup_argv[i], "-options")) {
+      while (++i < backup_argc)
+        if (!strcmp(backup_argv[i], "-f"))
+          use_default_torrc = 0;
+        smartlist_add(sl, backup_argv[i]);
+    }
+  }
+  if (use_default_torrc) {
+    smartlist_add(sl, "-f");
+    smartlist_add(sl, torrc);
+  }
+  tor_assert(smartlist_len(sl));
+  options = smartlist_join_strings(sl,"\" \"",0,NULL);
+  smartlist_free(sl);
+
+  /* Allocate a string for the NT service command line */
+  cmdlen = strlen(tor_exe)+ strlen(" --nt-service -f ")
+    + strlen(options) + 32;
+  command = tor_malloc(cmdlen);
+
+  /* Format the service command */
+  if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
+                   tor_exe, options)<0) {
+    tor_free(command); /* sets command to NULL. */
+  }
+  tor_free(options);
+  return command;
+}
+
+/** Creates a Tor NT service, set to start on boot. The service will be
+ * started if installation succeeds. Returns 0 on success, or -1 on
+ * failure. */
 int
 nt_service_install(void)
 {
-  /* XXXX Problems with NT services:
-   * 1. The configuration file needs to be in the same directory as the .exe
+  /* Notes about developing NT services:
    *
-   * 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:
-   *
    * 1. Don't count on your CWD. If an absolute path is not given, the
    *    fopen() function goes wrong.
    * 2. The parameters given to the nt_service_body() function differ
@@ -2096,47 +2093,24 @@
   SC_HANDLE hSCManager = NULL;
   SC_HANDLE hService = NULL;
   SERVICE_DESCRIPTION sdBuff;
-  TCHAR szPath[_MAX_PATH];
-  TCHAR szDrive[_MAX_DRIVE];
-  TCHAR szDir[_MAX_DIR];
-  char cmd1[] = " -f ";
-  char cmd2[] = "\\torrc";
   char *command;
   char *errmsg;
   int len = 0;
 
   if (nt_service_loadlibrary()<0)
     return -1;
-  if (0 == GetModuleFileName(NULL, szPath, MAX_PATH))
-    return 0;
 
-  _tsplitpath(szPath, szDrive, szDir, NULL, NULL);
-
-  /* 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) + 64;
-  command = tor_malloc(len);
-
-  /* Create a quoted command line, like "c:\with spaces\tor.exe" -f
-   * "c:\with spaces\tor.exe"
-   */
-  if (tor_snprintf(command, len, "\"%s\" --nt-service -f \"%s%storrc\"",
-                   szPath,  szDrive, szDir)<0) {
-    printf("Failed: tor_snprinf()\n");
-    tor_free(command);
-    return 0;
+  /* Open the service control manager so we can create a new service */
+  if ((hSCManager = nt_service_open_scm()) == NULL)
+    return -1;
+  /* Build the command line used for the service */
+  if ((command = nt_service_command_line()) == NULL) {
+    printf("Unable to build service command line.\n");
+    service_fns.CloseServiceHandle_fn(hSCManager);
+    return -1;
   }
 
-  if ((hSCManager = nt_service_open_scm()) == NULL) {
-    tor_free(command);
-    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.
-   */
+  /* Create the Tor service, set to auto-start on boot */
   if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
                                 GENSRV_DISPLAYNAME,
                                 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
@@ -2148,7 +2122,7 @@
     service_fns.CloseServiceHandle_fn(hSCManager);
     LocalFree(errmsg);
     tor_free(command);
-    return 0;
+    return -1;
   }
 
   /* Set the service's description */
@@ -2167,7 +2141,8 @@
   return 0;
 }
 
-/** DOCDOC */
+/** Removes the Tor NT service. Returns 0 if the service was successfully
+ * removed, or -1 on error. */
 int
 nt_service_remove(void)
 {
@@ -2177,37 +2152,31 @@
 
   if (nt_service_loadlibrary()<0)
     return -1;
-
-  if ((hSCManager = nt_service_open_scm()) == NULL) {
-    return 0;
-  }
-
+  if ((hSCManager = nt_service_open_scm()) == NULL)
+    return -1;
   if ((hService = nt_service_open(hSCManager)) == NULL) {
     service_fns.CloseServiceHandle_fn(hSCManager);
-    return 0;
+    return -1;
   }
 
-  if (nt_service_stop(hService)) {
-    if (service_fns.DeleteService_fn(hService)) {
-      printf("Removed service successfully\n");
-    }
-    else {
-      errmsg = nt_strerror(GetLastError());
-      printf("DeleteService() failed : %s\n", errmsg);
-      LocalFree(errmsg);
-    }
+  nt_service_stop(hService);
+  if (service_fns.DeleteService_fn(hService) == FALSE) {
+    errmsg = nt_strerror(GetLastError());
+    printf("DeleteService() failed : %s\n", errmsg);
+    LocalFree(errmsg);
+    service_fns.CloseServiceHandle_fn(hService);
+    service_fns.CloseServiceHandle_fn(hSCManager);
+    return -1;
   }
-  else {
-    printf("Service could not be removed\n");
-  }
 
   service_fns.CloseServiceHandle_fn(hService);
   service_fns.CloseServiceHandle_fn(hSCManager);
+  printf("Service removed successfully\n");
 
   return 0;
 }
 
-/** DOCDOC */
+/** Starts the Tor service. Returns 0 on success, or -1 on error. */
 int
 nt_service_cmd_start(void)
 {
@@ -2218,18 +2187,18 @@
   if ((hSCManager = nt_service_open_scm()) == NULL)
     return -1;
   if ((hService = nt_service_open(hSCManager)) == NULL) {
-    CloseHandle(hSCManager);
+    service_fns.CloseServiceHandle_fn(hSCManager);
     return -1;
   }
 
   start = nt_service_start(hService);
-  CloseHandle(hService);
-  CloseHandle(hSCManager);
+  service_fns.CloseServiceHandle_fn(hService);
+  service_fns.CloseServiceHandle_fn(hSCManager);
 
   return start;
 }
 
-/** DOCDOC */
+/** Stops the Tor service. Returns 0 on success, or -1 on error. */
 int
 nt_service_cmd_stop(void)
 {
@@ -2240,13 +2209,13 @@
   if ((hSCManager = nt_service_open_scm()) == NULL)
     return -1;
   if ((hService = nt_service_open(hSCManager)) == NULL) {
-    CloseHandle(hSCManager);
+    service_fns.CloseServiceHandle_fn(hSCManager);
     return -1;
   }
 
   stop = nt_service_stop(hService);
-  CloseHandle(hService);
-  CloseHandle(hSCManager);
+  service_fns.CloseServiceHandle_fn(hService);
+  service_fns.CloseServiceHandle_fn(hSCManager);
 
   return stop;
 }

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2006-12-24 06:32:20 UTC (rev 9184)
+++ tor/trunk/src/or/or.h	2006-12-24 06:32:24 UTC (rev 9185)
@@ -1221,7 +1221,7 @@
  * OR connections multiplex many circuits at once, and stay standing even
  * when there are no circuits running over them.
  *
- * A circuit_t structure cann fill one of two roles.  First, a or_circuit_t
+ * A circuit_t structure can fill one of two roles.  First, a or_circuit_t
  * links two connections together: either an edge connection and an OR
  * connection, or two OR connections.  (When joined to an OR connection, a
  * circuit_t affects only cells sent to a particular circID on that