//============================================================================= /** * @file Locator_Options.cpp * * @author Darrell Brunsch */ //============================================================================= #include "Locator_Options.h" #include "ace/Arg_Shifter.h" #include "orbsvcs/Log_Macros.h" #include "ace/OS_NS_strings.h" #if defined (ACE_WIN32) static const HKEY SERVICE_REG_ROOT = HKEY_LOCAL_MACHINE; // This string must agree with the one used in Locator_NT_Service.h static const ACE_TCHAR *SERVICE_REG_PATH = ACE_TEXT ("SYSTEM\\CurrentControlSet\\Services\\TAOImR\\Parameters"); #endif /* ACE_WIN32 */ static const int DEFAULT_PING_INTERVAL = 10; // seconds static const int DEFAULT_PING_TIMEOUT = 1; // seconds static const int DEFAULT_START_TIMEOUT = 60; // seconds static const long DEFAULT_FT_UPDATE_DELAY = 0; //250000; // useconds Options::Options () : repo_mode_ (REPO_NONE) , erase_repo_ (false) , debug_ (0) , multicast_ (false) , service_ (false) , ping_external_ (false) , ping_interval_ (DEFAULT_PING_INTERVAL) , ping_timeout_ (DEFAULT_PING_TIMEOUT) , startup_timeout_ (DEFAULT_START_TIMEOUT) , readonly_ (false) , service_command_ (SC_NONE) , unregister_if_address_reused_ (false) , lockout_ (false) , imr_type_ (STANDALONE_IMR) , throw_shutdown_exceptions_ (false) , pinger_ (0) , ft_endpoint_ () , ft_update_delay_ (0, DEFAULT_FT_UPDATE_DELAY) { } int Options::parse_args (int &argc, ACE_TCHAR *argv[]) { ACE_Arg_Shifter shifter (argc, argv); // Don't let persistence options co-mingle. bool binary_persistence_used = false; bool xml_persistence_used = false; bool directory_persistence_used = false; while (shifter.is_anything_left ()) { if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-c")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, "Error: -c option needs a command\n")); this->print_usage (); return -1; } if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("install")) == 0) { this->service_command_ = SC_INSTALL; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("remove")) == 0) { this->service_command_ = SC_REMOVE; } else { ORBSVCS_ERROR (( LM_ERROR, ACE_TEXT ("Error: Unknown service command : %s\n"), shifter.get_current ())); this->print_usage (); return -1; } } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-d")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, "Error: -d option needs a debuglevel\n")); this->print_usage (); return -1; } this->debug_ = ACE_OS::atoi (shifter.get_current ()); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-m")) == 0) { this->multicast_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-o")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, "Error: -o option needs a filename\n")); this->print_usage (); return -1; } this->ior_output_file_ = shifter.get_current(); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-s")) == 0) { // Run as a service this->service_ = true; } else if ((ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-?")) == 0) || (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-h")) == 0)) { this->print_usage (); return 1; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-l")) == 0) { this->readonly_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-p")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, "Error: -p option needs a filename\n")); this->print_usage (); return -1; } this->persist_file_name_ = shifter.get_current (); this->repo_mode_ = REPO_HEAP_FILE; binary_persistence_used = true; } else if ((ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-UnregisterIfAddressReused")) == 0) || (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--UnregisterIfAddressReused")) == 0) || (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-u")) == 0)) { this->unregister_if_address_reused_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--lockout")) == 0) { this->lockout_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-r")) == 0) { this->repo_mode_ = REPO_REGISTRY; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-x")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, "Error: -x option needs a filename\n")); this->print_usage (); return -1; } this->persist_file_name_ = shifter.get_current (); this->repo_mode_ = REPO_XML_FILE; xml_persistence_used = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--primary")) == 0) { this->imr_type_ = PRIMARY_IMR; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--backup")) == 0) { this->imr_type_ = BACKUP_IMR; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--directory")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: --directory option needs a filename\n"))); this->print_usage (); return -1; } this->persist_file_name_ = shifter.get_current (); this->repo_mode_ = REPO_SHARED_FILES; if (this->persist_file_name_.length() && this->persist_file_name_[this->persist_file_name_.length() - 1] != '/') { this->persist_file_name_ += '/'; } directory_persistence_used = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-e")) == 0) { this->erase_repo_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-t")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: -t option needs a value\n"))); this->print_usage (); return -1; } this->startup_timeout_ = ACE_Time_Value (ACE_OS::atoi (shifter.get_current ())); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-i")) == 0) { this->ping_external_ = true; } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-v")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: -v option needs a value\n"))); this->print_usage (); return -1; } this->ping_interval_ = ACE_Time_Value (0, 1000 * ACE_OS::atoi (shifter.get_current ())); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-n")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: -n option needs a value\n"))); this->print_usage (); return -1; } this->ping_timeout_ = ACE_Time_Value (0, 1000 * ACE_OS::atoi (shifter.get_current ())); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--ftendpoint")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: --FtEndpoint option needs a value\n"))); this->print_usage (); return -1; } this->ft_endpoint_ = ACE_TEXT_ALWAYS_CHAR (shifter.get_current ()); } else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("--ftupdatedelay")) == 0) { shifter.consume_arg (); if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Error: -FtUpdateDelay option needs a value\n"))); this->print_usage (); return -1; } this->ft_update_delay_ = ACE_Time_Value (0, 1000 * ACE_OS::atoi (shifter.get_current ())); } else { shifter.ignore_arg (); continue; } shifter.consume_arg (); } if ((this->imr_type_ == BACKUP_IMR || this->imr_type_ == PRIMARY_IMR) && !directory_persistence_used) { ORBSVCS_ERROR ((LM_ERROR, "Error: Redundancy is used but the " "--directory option is not passed\n")); this->print_usage (); return -1; } if ((binary_persistence_used + directory_persistence_used + xml_persistence_used) > 1) { ORBSVCS_ERROR ((LM_ERROR, "Error: Only one persistence option can be used\n")); this->print_usage (); return -1; } return 0; } int Options::init (int argc, ACE_TCHAR *argv[]) { // Make an initial pass through and grab the arguments that we recognize. // This may also run the commands to install or remove the nt service. int result = this->parse_args (argc, argv); if (result != 0) { return result; } for (int i = 0; i < argc; ++i) { this->cmdline_ += ACE_CString (ACE_TEXT_ALWAYS_CHAR(argv[i])) + ACE_CString (" "); } return 0; } int Options::init_from_registry (void) { this->load_registry_options (); return 0; } void Options::print_usage (void) const { ORBSVCS_ERROR ((LM_ERROR, ACE_TEXT ("Usage:\n") ACE_TEXT ("\n") ACE_TEXT ("ImplRepo_Service [-c cmd] [-d 0..5] [-e] [-m] [-o file]\n") ACE_TEXT (" [-r|-p file|-x file|--directory dir [--primary|--backup] ]\n") ACE_TEXT (" [-s] [-t secs] [-v msecs]\n") ACE_TEXT (" -c command Runs nt service commands ('install' or 'remove')\n") ACE_TEXT (" -d level Sets the debug level (default 0)\n") ACE_TEXT (" -e Erase the persisted repository at startup\n") ACE_TEXT (" -l Lock the database as read only\n") ACE_TEXT (" -m Turn on multicast\n") ACE_TEXT (" -o file Outputs the ImR's IOR to a file\n") ACE_TEXT (" -p file Use file for storing/loading settings\n") ACE_TEXT (" -x file Use XML file for storing/loading settings\n") ACE_TEXT (" --directory dir Use individual XML files for storing/loading\n") ACE_TEXT (" settings in the provided directory\n") ACE_TEXT (" --primary Replicate the ImplRepo as the primary ImR\n") ACE_TEXT (" --backup Replicate the ImplRepo as the backup ImR\n") ACE_TEXT (" -r Use the registry for storing/loading settings\n") ACE_TEXT (" -s Run as a service\n") ACE_TEXT (" -t secs Server startup timeout.(Default = 60s)\n") ACE_TEXT (" -v msecs Server verification interval.(Default = 10000ms)\n") ACE_TEXT (" -n msecs Ping request timeout.(Default = 10ms)\n") ACE_TEXT (" -i Ping servers started without activators too.\n") ACE_TEXT (" --lockout Prevent excessive restart attempts until manual reset.\n") ACE_TEXT (" --UnregisterIfAddressReused,\n") ACE_TEXT (" -u Unregister server if its endpoint is used by another\n") )); } int Options::save_registry_options () { #if defined (ACE_WIN32) HKEY key = 0; // Create or open the parameters key LONG err = ACE_TEXT_RegCreateKeyEx (SERVICE_REG_ROOT, SERVICE_REG_PATH, 0, const_cast (ACE_TEXT ("")), // class REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &key, 0 ); if (err != ERROR_SUCCESS) { return -1; } err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("ORBInitOptions"), 0, REG_SZ, (LPBYTE) this->cmdline_.c_str (), (DWORD) this->cmdline_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("IORFile"), 0, REG_SZ, (LPBYTE) ior_output_file_.c_str (), (DWORD) ior_output_file_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("DebugLevel"), 0, REG_DWORD, (LPBYTE) &debug_ , sizeof (debug_)); ACE_ASSERT(err == ERROR_SUCCESS); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PersistFile"), 0, REG_SZ, (LPBYTE) this->persist_file_name_.c_str (), (DWORD) this->persist_file_name_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); DWORD tmp = this->ping_external_ ? 1 : 0; err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PingExternals"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->ping_interval_.msec (); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PingInterval"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->ping_timeout_.msec (); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PingTimeout"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->readonly_ ? 1 : 0; err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Lock"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->lockout_ ? 1 : 0; err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("LockOut"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->repo_mode_; err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PersistType"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = static_cast (this->startup_timeout_.sec()); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Timeout"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->multicast_ ? 1 : 0; err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Multicast"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("ImrType"), 0, REG_DWORD, (LPBYTE) &this->imr_type_ , sizeof (this->imr_type_)); ACE_ASSERT (err == ERROR_SUCCESS); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("FtEndpoint"), 0, REG_SZ, (LPBYTE) this->ft_endpoint_.c_str (), (DWORD) this->ft_endpoint_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->ft_update_delay_.msec (); err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("FtUpdateDelay"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); err = ::RegCloseKey (key); ACE_ASSERT (err == ERROR_SUCCESS); #endif return 0; } int Options::load_registry_options () { #if defined (ACE_WIN32) HKEY key = 0; // Create or open the parameters key LONG err = ACE_TEXT_RegOpenKeyEx (SERVICE_REG_ROOT, SERVICE_REG_PATH, 0, KEY_READ, &key ); if (err != ERROR_SUCCESS) { // If there aren't any saved parameters, then that's ok. return 0; } ACE_TCHAR tmpstr[4096]; DWORD sz = sizeof (tmpstr); DWORD type = 0; err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("ORBInitOptions"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_SZ); tmpstr[sz - 1] = '\0'; this->cmdline_ = ACE_TEXT_ALWAYS_CHAR(tmpstr); } sz = sizeof(tmpstr); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("IORFile"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_SZ); tmpstr[sz - 1] = '\0'; this->ior_output_file_ = tmpstr; } sz = sizeof(debug_); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("DebugLevel"), 0, &type, (LPBYTE) &this->debug_ , &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); } DWORD tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PingExternal"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); ping_external_ = tmp != 0; } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PingInterval"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); ping_interval_.msec (static_cast (tmp)); } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PingTimeout"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); ping_timeout_.msec (static_cast (tmp)); } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Lock"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); readonly_ = tmp != 0; } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("LockOut"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); lockout_ = tmp != 0; } sz = sizeof(this->repo_mode_); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PersistType"), 0, &type, (LPBYTE) &this->repo_mode_, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Timeout"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); this->startup_timeout_.sec (tmp); } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Multicast"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); this->multicast_ = tmp != 0; } sz = sizeof(tmpstr); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PersistFile"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_SZ); tmpstr[sz - 1] = '\0'; this->persist_file_name_ = tmpstr; } sz = sizeof(imr_type_); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("ImrType"), 0, &type, (LPBYTE) &this->imr_type_ , &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); } sz = sizeof(tmpstr); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("FtEndpoint"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_SZ); tmpstr[sz - 1] = '\0'; this->ft_endpoint_ = ACE_TEXT_ALWAYS_CHAR (tmpstr); } tmp = 0; sz = sizeof(tmp); err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("FtUpdateDelay"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { ACE_ASSERT (type == REG_DWORD); ft_update_delay_.msec (static_cast (tmp)); } err = ::RegCloseKey (key); ACE_ASSERT (err == ERROR_SUCCESS); #endif return 0; } bool Options::service (void) const { return this->service_; } unsigned int Options::debug (void) const { return this->debug_; } const ACE_TString& Options::ior_filename (void) const { return this->ior_output_file_; } bool Options::multicast (void) const { return this->multicast_; } Options::SERVICE_COMMAND Options::service_command(void) const { return this->service_command_; } const char* Options::cmdline(void) const { return this->cmdline_.c_str (); } const ACE_TString& Options::persist_file_name(void) const { return this->persist_file_name_; } ACE_Time_Value Options::startup_timeout (void) const { return this->startup_timeout_; } bool Options::ping_external (void) const { return this->ping_external_; } ACE_Time_Value Options::ping_interval (void) const { return this->ping_interval_; } ACE_Time_Value Options::ping_timeout (void) const { return this->ping_timeout_; } LiveCheck * Options::pinger (void) const { return this->pinger_; } void Options::pinger (LiveCheck *p) { this->pinger_ = p; } Options::RepoMode Options::repository_mode (void) const { return this->repo_mode_; } bool Options::repository_erase (void) const { return this->erase_repo_; } bool Options::readonly (void) const { return this->readonly_; } bool Options::unregister_if_address_reused (void) const { return this->unregister_if_address_reused_; } bool Options::lockout (void) const { return this->lockout_; } bool Options::throw_shutdown_exceptions (void) const { return this->throw_shutdown_exceptions_; } Options::ImrType Options::imr_type (void) const { return this->imr_type_; } const ACE_CString & Options::ft_endpoint (void) const { return this->ft_endpoint_; } ACE_Time_Value Options::ft_update_delay (void) const { return this->ft_update_delay_; }