00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <boost/filesystem/operations.hpp>
00021 #include <pion/PionPlugin.hpp>
00022 #include <pion/PionLogger.hpp>
00023 #include "PlatformConfig.hpp"
00024 #ifndef _MSC_VER
00025 #include <fstream>
00026 #include <unistd.h>
00027 #include <sys/types.h>
00028 #include <boost/regex.hpp>
00029 #include <boost/tokenizer.hpp>
00030 #include <boost/lexical_cast.hpp>
00031 #endif
00032
00033 using namespace pion::net;
00034 using namespace pion::platform;
00035
00036
00037 namespace pion {
00038 namespace server {
00039
00040
00041
00042
00043 const std::string PlatformConfig::DEFAULT_CONFIG_FILE = "platform.xml";
00044 const std::string PlatformConfig::VERSION_ELEMENT_NAME = "Version";
00045 const std::string PlatformConfig::PLATFORM_CONFIG_ELEMENT_NAME = "PlatformConfig";
00046 const std::string PlatformConfig::VOCABULARY_CONFIG_ELEMENT_NAME = "VocabularyConfig";
00047 const std::string PlatformConfig::CODEC_CONFIG_ELEMENT_NAME = "CodecConfig";
00048 const std::string PlatformConfig::PROTOCOL_CONFIG_ELEMENT_NAME = "ProtocolConfig";
00049 const std::string PlatformConfig::DATABASE_CONFIG_ELEMENT_NAME = "DatabaseConfig";
00050 const std::string PlatformConfig::REACTOR_CONFIG_ELEMENT_NAME = "ReactorConfig";
00051 const std::string PlatformConfig::SERVICE_CONFIG_ELEMENT_NAME = "ServiceConfig";
00052 const std::string PlatformConfig::USER_CONFIG_ELEMENT_NAME = "UserConfig";
00053 const std::string PlatformConfig::LOG_CONFIG_ELEMENT_NAME = "LogConfig";
00054 const std::string PlatformConfig::VOCABULARY_PATH_ELEMENT_NAME = "VocabularyPath";
00055 const std::string PlatformConfig::PLUGIN_PATH_ELEMENT_NAME = "PluginPath";
00056 const std::string PlatformConfig::DATA_DIRECTORY_ELEMENT_NAME = "DataDirectory";
00057 const std::string PlatformConfig::DEBUG_MODE_ELEMENT_NAME = "DebugMode";
00058 const std::string PlatformConfig::REACTION_ENGINE_ELEMENT_NAME = "ReactionEngine";
00059 const std::string PlatformConfig::MAX_THREADS_ELEMENT_NAME = "MaxThreads";
00060 const std::string PlatformConfig::MULTITHREAD_BRANCHES_ELEMENT_NAME = "MultithreadBranches";
00061 const std::string PlatformConfig::USER_ELEMENT_NAME = "User";
00062 const std::string PlatformConfig::GROUP_ELEMENT_NAME = "Group";
00063
00064
00065
00066
00067 PlatformConfig::PlatformConfig(void)
00068 : ConfigManager(DEFAULT_CONFIG_FILE),
00069 m_vocab_mgr(), m_codec_factory(m_vocab_mgr),
00070 m_protocol_factory(m_vocab_mgr), m_database_mgr(m_vocab_mgr),
00071 m_reaction_engine(m_vocab_mgr, m_codec_factory, m_protocol_factory, m_database_mgr),
00072 m_service_mgr(m_vocab_mgr, *this), m_user_mgr_ptr(new UserManager),
00073 m_user_id(-1), m_group_id(-1), m_debug_mode(false)
00074 {
00075 setLogger(PION_GET_LOGGER("pion.server.PlatformConfig"));
00076 }
00077
00078 boost::int32_t PlatformConfig::findSystemId(const std::string& name,
00079 const std::string& file)
00080 {
00081 #ifdef _MSC_VER
00082 return -1;
00083 #else
00084
00085
00086 const boost::regex just_numbers("\\d+");
00087 if (boost::regex_match(name, just_numbers)) {
00088 return boost::lexical_cast<boost::int32_t>(name);
00089 }
00090
00091
00092 std::ifstream system_file(file.c_str());
00093 if (! system_file.is_open()) {
00094 PION_LOG_ERROR(m_logger, "Unable to open " << file << " file");
00095 return -1;
00096 }
00097
00098
00099 typedef boost::tokenizer<boost::char_separator<char> > Tok;
00100 boost::char_separator<char> sep(":");
00101 std::string line;
00102 boost::int32_t system_id = -1;
00103
00104 while (std::getline(system_file, line, '\n')) {
00105 Tok tokens(line, sep);
00106 Tok::const_iterator token_it = tokens.begin();
00107 if (token_it != tokens.end() && *token_it == name) {
00108
00109 if (++token_it != tokens.end() && ++token_it != tokens.end()
00110 && boost::regex_match(*token_it, just_numbers))
00111 {
00112
00113 system_id = boost::lexical_cast<boost::int32_t>(*token_it);
00114 } else {
00115 PION_LOG_ERROR(m_logger, "Unexpected formatting in "
00116 << file << " file");
00117 }
00118 break;
00119 }
00120 }
00121
00122 if (system_id == -1) {
00123 PION_LOG_ERROR(m_logger, "Unable to find " << name
00124 << " in " << file << " file");
00125 }
00126
00127 return system_id;
00128 #endif
00129 }
00130
00131 void PlatformConfig::parseUser(void)
00132 {
00133 #ifdef _MSC_VER
00134 PION_LOG_ERROR(m_logger, "Windows not supported for user masquerading: " << m_user_name);
00135 #else
00136 m_user_id = findSystemId(m_user_name, "/etc/passwd");
00137 if (m_user_id != -1) {
00138 if ( seteuid(m_user_id) != 0 ) {
00139 PION_LOG_ERROR(m_logger, "Unable to run as user "
00140 << m_user_name << " (" << m_user_id << ")");
00141 } else {
00142 PION_LOG_INFO(m_logger, "Running as user "
00143 << m_user_name << " (" << m_user_id << ")");
00144 }
00145 } else {
00146 m_user_id = geteuid();
00147 }
00148 #endif
00149 }
00150
00151 void PlatformConfig::parseGroup(void)
00152 {
00153 #ifdef _MSC_VER
00154 PION_LOG_ERROR(m_logger, "Windows not supported for group masquerading: " << m_group_name);
00155 #else
00156 m_group_id = findSystemId(m_group_name, "/etc/group");
00157 if (m_group_id != -1) {
00158 if ( setegid(m_group_id) != 0 ) {
00159 PION_LOG_ERROR(m_logger, "Unable to run as group "
00160 << m_group_name << " (" << m_group_id << ")");
00161 } else {
00162 PION_LOG_INFO(m_logger, "Running as group "
00163 << m_group_name << " (" << m_group_id << ")");
00164 }
00165 } else {
00166 m_group_id = getegid();
00167 }
00168 #endif
00169 }
00170
00171 void PlatformConfig::openConfigFile(void)
00172 {
00173 boost::mutex::scoped_lock platform_lock(m_mutex);
00174
00175
00176 if (configIsOpen())
00177 return;
00178
00179
00180 ConfigManager::openConfigFile();
00181
00182 #if defined(PION_USE_LOG4CXX) || defined(PION_USE_LOG4CPLUS) || defined(PION_USE_LOG4CPP)
00183
00184 if (ConfigManager::getConfigOption(LOG_CONFIG_ELEMENT_NAME, m_log_config_file,
00185 m_config_node_ptr->children))
00186 {
00187
00188 m_log_config_file = ConfigManager::resolveRelativePath(m_log_config_file);
00189 PION_LOG_CONFIG(m_log_config_file);
00190 } else {
00191 m_log_config_file.erase();
00192 }
00193 #endif
00194
00195 #if defined(PION_USE_LOG4CPLUS)
00196
00197 PionLogAppenderPtr appender(new CircularBufferAppender);
00198 appender->setName("CircularBufferAppender");
00199 log4cplus::Logger::getRoot().addAppender(appender);
00200 #endif
00201
00202
00203
00204
00205 if (ConfigManager::getConfigOption(GROUP_ELEMENT_NAME, m_group_name,
00206 m_config_node_ptr->children))
00207 {
00208 parseGroup();
00209 }
00210
00211
00212 if (ConfigManager::getConfigOption(USER_ELEMENT_NAME, m_user_name,
00213 m_config_node_ptr->children))
00214 {
00215 parseUser();
00216 }
00217
00218
00219 m_plugin_paths.clear();
00220 std::string plugin_path;
00221 xmlNodePtr path_node = m_config_node_ptr->children;
00222 if (ConfigManager::findConfigNodeByName(PLUGIN_PATH_ELEMENT_NAME, path_node) != NULL)
00223 PionPlugin::resetPluginDirectories();
00224 while ( (path_node = ConfigManager::findConfigNodeByName(PLUGIN_PATH_ELEMENT_NAME, path_node)) != NULL)
00225 {
00226
00227 xmlChar *xml_char_ptr = xmlNodeGetContent(path_node);
00228 if (xml_char_ptr == NULL || xml_char_ptr[0]=='\0') {
00229 if (xml_char_ptr != NULL)
00230 xmlFree(xml_char_ptr);
00231 throw EmptyPluginPathException(getConfigFile());
00232 }
00233 plugin_path = reinterpret_cast<char*>(xml_char_ptr);
00234 xmlFree(xml_char_ptr);
00235
00236
00237 try {
00238 plugin_path = ConfigManager::resolveRelativePath(plugin_path);
00239 PionPlugin::addPluginDirectory(plugin_path);
00240 m_plugin_paths.push_back(plugin_path);
00241 } catch (PionPlugin::DirectoryNotFoundException& e) {
00242 PION_LOG_WARN(m_logger, e.what());
00243 }
00244
00245
00246 path_node = path_node->next;
00247 }
00248
00249
00250 std::string config_file;
00251 if (! ConfigManager::getConfigOption(VOCABULARY_CONFIG_ELEMENT_NAME, config_file,
00252 m_config_node_ptr->children))
00253 throw MissingVocabularyConfigException(getConfigFile());
00254
00255
00256 m_vocab_mgr.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00257 m_vocab_mgr.openConfigFile();
00258
00259
00260 if (! ConfigManager::getConfigOption(DATA_DIRECTORY_ELEMENT_NAME, m_data_directory,
00261 m_config_node_ptr->children))
00262 throw MissingDataDirectoryException(getConfigFile());
00263 m_data_directory = ConfigManager::resolveRelativePath(m_data_directory);
00264
00265
00266 std::string debug_str;
00267 if (ConfigManager::getConfigOption(DEBUG_MODE_ELEMENT_NAME, debug_str,
00268 m_config_node_ptr->children))
00269 {
00270 m_debug_mode = (debug_str == "true");
00271 if (m_debug_mode) {
00272 PION_LOG_WARN(m_logger, "Debugging mode enabled - do not use in production!");
00273 }
00274 } else {
00275 m_debug_mode = false;
00276 }
00277
00278
00279 if (! ConfigManager::getConfigOption(CODEC_CONFIG_ELEMENT_NAME, config_file,
00280 m_config_node_ptr->children))
00281 throw MissingCodecConfigException(getConfigFile());
00282
00283
00284 m_codec_factory.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00285 m_codec_factory.setDataDirectory(m_data_directory);
00286 m_codec_factory.setDebugMode(m_debug_mode);
00287 m_codec_factory.openConfigFile();
00288
00289
00290 if (! ConfigManager::getConfigOption(PROTOCOL_CONFIG_ELEMENT_NAME, config_file,
00291 m_config_node_ptr->children))
00292 throw MissingProtocolConfigException(getConfigFile());
00293
00294
00295 m_protocol_factory.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00296 m_protocol_factory.setDataDirectory(m_data_directory);
00297 m_protocol_factory.setDebugMode(m_debug_mode);
00298 m_protocol_factory.openConfigFile();
00299
00300
00301 if (! boost::filesystem::exists(m_data_directory) )
00302 throw DirectoryNotFoundException(m_data_directory);
00303 if (! boost::filesystem::is_directory(m_data_directory) )
00304 throw NotADirectoryException(m_data_directory);
00305
00306
00307 if (! ConfigManager::getConfigOption(DATABASE_CONFIG_ELEMENT_NAME, config_file,
00308 m_config_node_ptr->children))
00309 throw MissingDatabaseConfigException(getConfigFile());
00310
00311
00312 m_database_mgr.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00313 m_database_mgr.setDataDirectory(m_data_directory);
00314 m_database_mgr.setDebugMode(m_debug_mode);
00315 m_database_mgr.openConfigFile();
00316
00317
00318 if (! ConfigManager::getConfigOption(REACTOR_CONFIG_ELEMENT_NAME, config_file,
00319 m_config_node_ptr->children))
00320 throw MissingReactorConfigException(getConfigFile());
00321
00322
00323 xmlNodePtr reaction_engine_node =
00324 ConfigManager::findConfigNodeByName(REACTION_ENGINE_ELEMENT_NAME, m_config_node_ptr->children);
00325 if (reaction_engine_node != NULL) {
00326
00327 std::string max_threads_str;
00328 if (ConfigManager::getConfigOption(MAX_THREADS_ELEMENT_NAME, max_threads_str,
00329 reaction_engine_node->children))
00330 {
00331 const boost::uint32_t max_threads = boost::lexical_cast<boost::uint32_t>(max_threads_str);
00332 if (max_threads == 0) {
00333 PION_LOG_ERROR(m_logger, "Platform config has invalid MaxThreads setting for ReactionEngine (using default)");
00334 } else {
00335 PION_LOG_INFO(m_logger, "Setting ReactionEngine MaxThreads to " << max_threads);
00336 m_reaction_engine.setNumThreads(max_threads);
00337 }
00338 }
00339
00340
00341 std::string mt_branches_str;
00342 if (ConfigManager::getConfigOption(MULTITHREAD_BRANCHES_ELEMENT_NAME,
00343 mt_branches_str,
00344 reaction_engine_node->children))
00345 {
00346 if (mt_branches_str == "true") {
00347 PION_LOG_INFO(m_logger, "Enabling multithreaded branches in ReactionEngine");
00348 m_reaction_engine.setMultithreadBranches(true);
00349 } else if (mt_branches_str == "false") {
00350 PION_LOG_INFO(m_logger, "Disabling multithreaded branches in ReactionEngine");
00351 m_reaction_engine.setMultithreadBranches(false);
00352 } else {
00353 PION_LOG_ERROR(m_logger, "Platform config has invalid MultithreadBranches setting for ReactionEngine (using default)");
00354 }
00355 }
00356 }
00357
00358
00359 m_reaction_engine.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00360 m_reaction_engine.setDataDirectory(m_data_directory);
00361 m_reaction_engine.setDebugMode(m_debug_mode);
00362 m_reaction_engine.openConfigFile();
00363
00364
00365 if (! ConfigManager::getConfigOption(SERVICE_CONFIG_ELEMENT_NAME, config_file,
00366 m_config_node_ptr->children))
00367 throw MissingServiceConfigException(getConfigFile());
00368
00369
00370 m_service_mgr.setConfigFile(ConfigManager::resolveRelativePath(config_file));
00371 m_service_mgr.setDataDirectory(m_data_directory);
00372 m_service_mgr.setDebugMode(m_debug_mode);
00373 m_service_mgr.openConfigFile();
00374
00375
00376 if (! ConfigManager::getConfigOption(USER_CONFIG_ELEMENT_NAME, config_file,
00377 m_config_node_ptr->children))
00378 throw MissingUserConfigException(getConfigFile());
00379
00380
00381 m_user_mgr_ptr->setConfigFile(ConfigManager::resolveRelativePath(config_file));
00382 m_user_mgr_ptr->setDataDirectory(m_data_directory);
00383 m_user_mgr_ptr->setDebugMode(m_debug_mode);
00384 m_user_mgr_ptr->openConfigFile();
00385
00386 PION_LOG_INFO(m_logger, "Loaded platform configuration file: " << m_config_file);
00387 }
00388
00389 void PlatformConfig::writeConfigXML(std::ostream& out) const
00390 {
00391 ConfigManager::writeBeginPionConfigXML(out);
00392
00393 out << "\t<" << VERSION_ELEMENT_NAME << '>' << PION_VERSION
00394 << "</" << VERSION_ELEMENT_NAME << '>' << std::endl
00395 << "\t<" << DEBUG_MODE_ELEMENT_NAME << '>' << (m_debug_mode ? "true" : "false")
00396 << "</" << DEBUG_MODE_ELEMENT_NAME << '>' << std::endl
00397 << "\t<" << PLATFORM_CONFIG_ELEMENT_NAME << '>' << getConfigFile()
00398 << "</" << PLATFORM_CONFIG_ELEMENT_NAME << '>' << std::endl
00399 << "\t<" << VOCABULARY_CONFIG_ELEMENT_NAME << '>' << m_vocab_mgr.getConfigFile()
00400 << "</" << VOCABULARY_CONFIG_ELEMENT_NAME << '>' << std::endl
00401 << "\t<" << CODEC_CONFIG_ELEMENT_NAME << '>' << m_codec_factory.getConfigFile()
00402 << "</" << CODEC_CONFIG_ELEMENT_NAME << '>' << std::endl
00403 << "\t<" << PROTOCOL_CONFIG_ELEMENT_NAME << '>' << m_protocol_factory.getConfigFile()
00404 << "</" << PROTOCOL_CONFIG_ELEMENT_NAME << '>' << std::endl
00405 << "\t<" << DATABASE_CONFIG_ELEMENT_NAME << '>' << m_database_mgr.getConfigFile()
00406 << "</" << DATABASE_CONFIG_ELEMENT_NAME << '>' << std::endl
00407 << "\t<" << REACTOR_CONFIG_ELEMENT_NAME << '>' << m_reaction_engine.getConfigFile()
00408 << "</" << REACTOR_CONFIG_ELEMENT_NAME << '>' << std::endl
00409 << "\t<" << SERVICE_CONFIG_ELEMENT_NAME << '>' << m_service_mgr.getConfigFile()
00410 << "</" << SERVICE_CONFIG_ELEMENT_NAME << '>' << std::endl
00411 << "\t<" << USER_CONFIG_ELEMENT_NAME << '>' << m_user_mgr_ptr->getConfigFile()
00412 << "</" << USER_CONFIG_ELEMENT_NAME << '>' << std::endl
00413 << "\t<" << LOG_CONFIG_ELEMENT_NAME << '>' << getLogConfigFile()
00414 << "</" << LOG_CONFIG_ELEMENT_NAME << '>' << std::endl
00415 << "\t<" << VOCABULARY_PATH_ELEMENT_NAME << '>' << m_vocab_mgr.getVocabularyPath()
00416 << "</" << VOCABULARY_PATH_ELEMENT_NAME << '>' << std::endl
00417 << "\t<" << DATA_DIRECTORY_ELEMENT_NAME << '>' << m_data_directory
00418 << "</" << DATA_DIRECTORY_ELEMENT_NAME << '>' << std::endl;
00419
00420 boost::mutex::scoped_lock platform_lock(m_mutex);
00421 for (std::vector<std::string>::const_iterator path_it = m_plugin_paths.begin();
00422 path_it != m_plugin_paths.end(); ++path_it)
00423 {
00424 out << "\t<" << PLUGIN_PATH_ELEMENT_NAME << '>' << *path_it
00425 << "</" << PLUGIN_PATH_ELEMENT_NAME << '>' << std::endl;
00426 }
00427 platform_lock.unlock();
00428
00429 ConfigManager::writeEndPionConfigXML(out);
00430 }
00431
00432
00433 }
00434 }