⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntmain.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */

#define MAIN_PRIVATE
#include "or.h"

const char ntmain_c_id[] =
  "$Id$";

#include <tchar.h>
#define GENSRV_SERVICENAME  TEXT("tor")
#define GENSRV_DISPLAYNAME  TEXT("Tor Win32 Service")
#define GENSRV_DESCRIPTION  \
  TEXT("Provides an anonymous Internet communication system")
#define GENSRV_USERACCT TEXT("NT AUTHORITY\\LocalService")

// 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_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE

static SERVICE_STATUS service_status;
static SERVICE_STATUS_HANDLE hStatus;

/* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
 * is a job for arguments, not globals.  Alas, some of the functions that
 * use them use them need to have fixed signatures, so they can be passed
 * to the NT service functions. */
static char **backup_argv;
static int backup_argc;
static char* nt_strerror(uint32_t errnum);

static void nt_service_control(DWORD request);
static void nt_service_body(int argc, char **argv);
static void nt_service_main(void);
static SC_HANDLE nt_service_open_scm(void);
static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
static int nt_service_start(SC_HANDLE hService);
static int nt_service_stop(SC_HANDLE hService);
static int nt_service_install(int argc, char **argv);
static int nt_service_remove(void);
static int nt_service_cmd_start(void);
static int nt_service_cmd_stop(void);

/** Struct to hold dynamically loaded NT-service related function pointers.
 */
struct service_fns {
  int loaded;

  BOOL (WINAPI *ChangeServiceConfig2A_fn)(
                             SC_HANDLE hService,
                             DWORD dwInfoLevel,
                             LPVOID lpInfo);

  BOOL (WINAPI *CloseServiceHandle_fn)(
                             SC_HANDLE hSCObject);

  BOOL (WINAPI *ControlService_fn)(
                             SC_HANDLE hService,
                             DWORD dwControl,
                             LPSERVICE_STATUS lpServiceStatus);

  SC_HANDLE (WINAPI *CreateServiceA_fn)(
                             SC_HANDLE hSCManager,
                             LPCTSTR lpServiceName,
                             LPCTSTR lpDisplayName,
                             DWORD dwDesiredAccess,
                             DWORD dwServiceType,
                             DWORD dwStartType,
                             DWORD dwErrorControl,
                             LPCTSTR lpBinaryPathName,
                             LPCTSTR lpLoadOrderGroup,
                             LPDWORD lpdwTagId,
                             LPCTSTR lpDependencies,
                             LPCTSTR lpServiceStartName,
                             LPCTSTR lpPassword);

  BOOL (WINAPI *DeleteService_fn)(
                             SC_HANDLE hService);

  SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
                             LPCTSTR lpMachineName,
                             LPCTSTR lpDatabaseName,
                             DWORD dwDesiredAccess);

  SC_HANDLE (WINAPI *OpenServiceA_fn)(
                             SC_HANDLE hSCManager,
                             LPCTSTR lpServiceName,
                             DWORD dwDesiredAccess);

  BOOL (WINAPI *QueryServiceStatus_fn)(
                             SC_HANDLE hService,
                             LPSERVICE_STATUS lpServiceStatus);

  SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
                             LPCTSTR lpServiceName,
                             LPHANDLER_FUNCTION lpHandlerProc);

  BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
                             LPSERVICE_STATUS);

  BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
                             const SERVICE_TABLE_ENTRY* lpServiceTable);

  BOOL (WINAPI *StartServiceA_fn)(
                             SC_HANDLE hService,
                             DWORD dwNumServiceArgs,
                             LPCTSTR* lpServiceArgVectors);

  BOOL (WINAPI *LookupAccountNameA_fn)(
                             LPCTSTR lpSystemName,
                             LPCTSTR lpAccountName,
                             PSID Sid,
                             LPDWORD cbSid,
                             LPTSTR ReferencedDomainName,
                             LPDWORD cchReferencedDomainName,
                             PSID_NAME_USE peUse);
} service_fns = { 0,
                  NULL, NULL, NULL, NULL, NULL, NULL,
                  NULL, NULL, NULL, NULL, NULL, NULL,
                  NULL};

/** Loads functions used by NT services. Returns on success, or prints a
 * complaint to stdout and exits on error. */
static void
nt_service_loadlibrary(void)
{
  HMODULE library = 0;
  void *fn;

  if (service_fns.loaded)
    return;

  /* XXXX Possibly, we should hardcode the location of this DLL. */
  if (!(library = LoadLibrary("advapi32.dll"))) {
    log_err(LD_GENERAL, "Couldn't open advapi32.dll.  Are you trying to use "
            "NT services on Windows 98? That doesn't work.");
    goto err;
  }

#define LOAD(f) STMT_BEGIN                                              \
    if (!(fn = GetProcAddress(library, #f))) {                          \
      log_err(LD_BUG,                                                   \
              "Couldn't find %s in advapi32.dll! We probably got the "  \
              "name wrong.", #f);                                       \
      goto err;                                                         \
    } else {                                                            \
      service_fns.f ## _fn = fn;                                        \
    }                                                                   \
  STMT_END

  LOAD(ChangeServiceConfig2A);
  LOAD(CloseServiceHandle);
  LOAD(ControlService);
  LOAD(CreateServiceA);
  LOAD(DeleteService);
  LOAD(OpenSCManagerA);
  LOAD(OpenServiceA);
  LOAD(QueryServiceStatus);
  LOAD(RegisterServiceCtrlHandlerA);
  LOAD(SetServiceStatus);
  LOAD(StartServiceCtrlDispatcherA);
  LOAD(StartServiceA);
  LOAD(LookupAccountNameA);

  service_fns.loaded = 1;

  return;
 err:
  printf("Unable to load library support for NT services: exiting.\n");
  exit(1);
}

/** If we're compiled to run as an NT service, and the service wants to
 * shut down, then change our current status and return 1.  Else
 * return 0.
 */
int
nt_service_is_stopping(void)
/* XXXX this function would probably _love_ to be inline, in 0.2.0. */
{
  /* If we haven't loaded the function pointers, we can't possibly be an NT
   * service trying to shut down. */
  if (!service_fns.loaded)
    return 0;

  if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
    service_status.dwWin32ExitCode = 0;
    service_status.dwCurrentState = SERVICE_STOPPED;
    service_fns.SetServiceStatus_fn(hStatus, &service_status);
    return 1;
  } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
    return 1;
  }
  return 0;
}

/** Set the dwCurrentState field for our service to <b>state</b>. */
void
nt_service_set_state(DWORD state)
{
  service_status.dwCurrentState = state;
}

/** Handles service control requests, such as stopping or starting the
 * Tor service. */
static void
nt_service_control(DWORD request)
{
  static struct timeval exit_now;
  exit_now.tv_sec  = 0;
  exit_now.tv_usec = 0;

  nt_service_loadlibrary();

  switch (request) {
    case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
          log_notice(LD_GENERAL,
                     "Got stop/shutdown request; shutting down cleanly.");
          service_status.dwCurrentState = SERVICE_STOP_PENDING;
          event_loopexit(&exit_now);
          return;
  }
  service_fns.SetServiceStatus_fn(hStatus, &service_status);
}

/** 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. */
static void
nt_service_body(int argc, char **argv)
{
  int r;
  (void) argc; /* unused */
  (void) argv; /* unused */
  nt_service_loadlibrary();
  service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  service_status.dwCurrentState = SERVICE_START_PENDING;
  service_status.dwControlsAccepted =
        SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  service_status.dwWin32ExitCode = 0;
  service_status.dwServiceSpecificExitCode = 0;
  service_status.dwCheckPoint = 0;
  service_status.dwWaitHint = 1000;
  hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
                                   (LPHANDLER_FUNCTION) nt_service_control);

  if (hStatus == 0) {
    /* Failed to register the service control handler function */
    return;
  }

  r = tor_init(backup_argc, backup_argv);
  if (r) {
    /* 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();
}

/** Main service entry point. Starts the service control dispatcher and waits
 * until the service status is set to SERVICE_STOPPED. */
static void
nt_service_main(void)
{
  SERVICE_TABLE_ENTRY table[2];
  DWORD result = 0;
  char *errmsg;
  nt_service_loadlibrary();
  table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
  table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
  table[1].lpServiceName = NULL;
  table[1].lpServiceProc = NULL;

  if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
    result = GetLastError();
    errmsg = nt_strerror(result);
    printf("Service error %d : %s\n", (int) result, errmsg);
    LocalFree(errmsg);
    if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
      if (tor_init(backup_argc, backup_argv) < 0)
        return;
      switch (get_options()->command) {
      case CMD_RUN_TOR:
        do_main_loop();
        break;
      case CMD_LIST_FINGERPRINT:
      case CMD_HASH_PASSWORD:
      case CMD_VERIFY_CONFIG:
        log_err(LD_CONFIG, "Unsupported command (--list-fingerint, "
                "--hash-password, or --verify-config) in NT service.");
        break;
      case CMD_RUN_UNITTESTS:
      default:
        log_err(LD_CONFIG, "Illegal command number %d: internal error.",
                get_options()->command);
      }
      tor_cleanup();
    }
  }
}

/** Return a handle to the service control manager on success, or NULL on
 * failure. */
static SC_HANDLE
nt_service_open_scm(void)
{
  SC_HANDLE hSCManager;
  char *errmsg = NULL;

  nt_service_loadlibrary();
  if ((hSCManager = service_fns.OpenSCManagerA_fn(
                            NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
    errmsg = nt_strerror(GetLastError());
    printf("OpenSCManager() failed : %s\n", errmsg);
    LocalFree(errmsg);
  }
  return hSCManager;
}

/** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
 * on failure. */
static SC_HANDLE
nt_service_open(SC_HANDLE hSCManager)
{
  SC_HANDLE hService;
  char *errmsg = NULL;
  nt_service_loadlibrary();
  if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
                              SERVICE_ALL_ACCESS)) == NULL) {
    errmsg = nt_strerror(GetLastError());
    printf("OpenService() failed : %s\n", errmsg);
    LocalFree(errmsg);
  }
  return hService;
}

/** Start the Tor service. Return 0 if the service is started or was
 * previously running. Return -1 on error. */
static int
nt_service_start(SC_HANDLE hService)
{
  char *errmsg = NULL;

  nt_service_loadlibrary();

  service_fns.QueryServiceStatus_fn(hService, &service_status);
  if (service_status.dwCurrentState == SERVICE_RUNNING) {
    printf("Service is already running\n");
    return 0;
  }

  if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
    /* Loop until the service has finished attempting to start */
    while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
           (service_status.dwCurrentState == SERVICE_START_PENDING)) {
      Sleep(500);
    }

    /* Check if it started successfully or not */
    if (service_status.dwCurrentState == SERVICE_RUNNING) {
      printf("Service started successfully\n");
      return 0;
    } else {
      errmsg = nt_strerror(service_status.dwWin32ExitCode);
      printf("Service failed to start : %s\n", errmsg);
      LocalFree(errmsg);
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -