mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
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 svn:r9185
This commit is contained in:
parent
c12a1f1e3a
commit
bae366eff0
@ -12,6 +12,10 @@ Changes in version 0.1.2.5-xxxx - 200?-??-??
|
||||
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 @@ Changes in version 0.1.2.5-xxxx - 200?-??-??
|
||||
- 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.
|
||||
|
259
src/or/main.c
259
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) {
|
||||
/* Failed to start the Tor service */
|
||||
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;
|
||||
}
|
||||
|
||||
if (r) {
|
||||
// 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;
|
||||
/* 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 @@ 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 {
|
||||
nt_service_stop(hService);
|
||||
if (service_fns.DeleteService_fn(hService) == FALSE) {
|
||||
errmsg = nt_strerror(GetLastError());
|
||||
printf("DeleteService() failed : %s\n", errmsg);
|
||||
LocalFree(errmsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Service could not be removed\n");
|
||||
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;
|
||||
}
|
||||
|
@ -1221,7 +1221,7 @@ typedef uint16_t circid_t;
|
||||
* 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
|
||||
|
Loading…
Reference in New Issue
Block a user