aboutsummaryrefslogtreecommitdiff
path: root/src/or/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/main.c')
-rw-r--r--src/or/main.c269
1 files changed, 119 insertions, 150 deletions
diff --git a/src/or/main.c b/src/or/main.c
index d134bb392..c67dcd753 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -78,7 +78,6 @@ int has_completed_circuit=0;
// 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 @@ struct service_fns {
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 @@ nt_service_loadlibrary(void)
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 @@ nt_service_is_stopped(void)
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 @@ nt_service_control(DWORD request)
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 @@ nt_service_body(int argc, char **argv)
(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 @@ nt_service_main(void)
}
}
-/** 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 @@ nt_service_open_scm(void)
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 @@ nt_service_open(SC_HANDLE hSCManager)
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 @@ nt_service_start(SC_HANDLE hService)
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 @@ nt_service_start(SC_HANDLE hService)
/* 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 @@ nt_service_start(SC_HANDLE hService)
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 @@ nt_service_stop(SC_HANDLE hService)
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 @@ nt_service_stop(SC_HANDLE hService)
}
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,32 +2018,71 @@ nt_service_stop(SC_HANDLE hService)
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
- *
- * 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:
+ /* Notes about developing NT services:
*
* 1. Don't count on your CWD. If an absolute path is not given, the
* fopen() function goes wrong.
@@ -2096,47 +2093,24 @@ nt_service_install(void)
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;
- }
- if ((hSCManager = nt_service_open_scm()) == NULL) {
- 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;
}
- /* 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 @@ nt_service_install(void)
service_fns.CloseServiceHandle_fn(hSCManager);
LocalFree(errmsg);
tor_free(command);
- return 0;
+ return -1;
}
/* Set the service's description */
@@ -2167,7 +2141,8 @@ nt_service_install(void)
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 @@ nt_service_remove(void)
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);
- }
- }
- else {
- printf("Service could not be removed\n");
+ 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;
}
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 @@ nt_service_cmd_start(void)
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 @@ nt_service_cmd_stop(void)
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;
}