00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00024 #include "config.h"
00025
00026 #include <algorithm>
00027 #include <cerrno>
00028 #include <cstring>
00029 #include <exception>
00030 #include <fstream>
00031 #include <functional>
00032 #include <iostream>
00033 #include <memory>
00034 #include <signal.h>
00035 #include <unistd.h>
00036
00037 #include <scalestack/kernel/core.h>
00038 #include <scalestack/kernel/delete_pointer.h>
00039 #include <scalestack/kernel/exception.h>
00040 #include <scalestack/kernel/log_console.h>
00041 #include <scalestack/kernel/module.h>
00042
00043 using namespace std;
00044
00045 namespace scalestack
00046 {
00047 namespace kernel
00048 {
00049
00055 static core* global_kernel_core = NULL;
00056
00063 extern "C" void global_signal_handler(int signal_number);
00064 extern "C" void global_signal_handler(int signal_number)
00065 {
00066 global_kernel_core->handle_signal(signal_number);
00067 }
00068
00069
00070
00071
00072
00073 core::core(void):
00074 logger(0),
00075 _need_help(),
00076 _need_config(),
00077 _shutdown_request(),
00078 _iterator_on_modules(),
00079 _notify_pipe(),
00080 _open_files(),
00081 _paths(),
00082 _modules(),
00083 _new_modules(),
00084 _module_iterator(_modules.begin()),
00085 _aliases(),
00086 _services(),
00087 _logs()
00088 {
00089 if (pipe(_notify_pipe) == -1)
00090 log_fatal(_("Failed pipe: %s:%d"), strerror(errno), errno);
00091
00092
00093 _paths.push_back(SCALESTACK_QUOTE_VALUE(SCALESTACK_MODULE_PATH));
00094
00095
00096 auto_ptr<log> console(new log_console());
00097 add_log("console", console.get());
00098 console.release();
00099 }
00100
00101 core::~core()
00102 {
00103 log_info(_("Destructing the core object"));
00104
00105 for_each(_new_modules.begin(), _new_modules.end(), mem_fun(&module::_unload));
00106 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_unload));
00107 for_each(_new_modules.begin(), _new_modules.end(), delete_pointer());
00108 for_each(_modules.begin(), _modules.end(), delete_pointer());
00109
00110 if (get_service_count() != 0)
00111 {
00112 for (services::const_iterator service = _services.begin();
00113 service != _services.end();
00114 ++service)
00115 {
00116 log_error(_("Service still exists: %s"), service->first.c_str());
00117 }
00118 }
00119
00120
00121 if (get_log_count() != 1)
00122 {
00123 for (logs::const_iterator log = _logs.begin(); log != _logs.end(); ++log)
00124 log_error(_("Log still exists: %s"), log->first.c_str());
00125 }
00126
00127 log_info(_("Destructed core object"));
00128
00129 delete remove_log("console");
00130
00131
00132 if (global_kernel_core == this)
00133 global_kernel_core = NULL;
00134
00135 close(_notify_pipe[0]);
00136 close(_notify_pipe[1]);
00137 }
00138
00139 void core::parse_arguments(int argument_count, const char** arguments)
00140 {
00141
00142
00143
00144
00145
00146 for (int current = 0; current < argument_count; current++)
00147 {
00148 string argument(arguments[current]);
00149
00150 size_t module_offset = argument.find_first_not_of("-");
00151 if (module_offset == string::npos)
00152 log_fatal(_("Bad command line option: %s"), argument.c_str());
00153 else if (module_offset > 0)
00154 argument.erase(0, module_offset);
00155
00156
00157 if (argument.find_first_not_of("v") == string::npos)
00158 _threshold += argument.size();
00159
00160
00161 size_t value_offset = argument.find("=");
00162 if (value_offset != string::npos)
00163 {
00164 if (string(argument, 0, value_offset) == "v")
00165 _threshold = atoi(string(argument, value_offset + 1).c_str());
00166 }
00167 }
00168
00169
00170 for (int current = 0; current < argument_count; current++)
00171 _parse_argument(arguments[current]);
00172 }
00173
00174 void core::parse_file(const std::string& filename)
00175 {
00176 log_info(_("Parsing file: %s"), filename.c_str());
00177
00178 string full_filename;
00179 if (_open_files.empty() || filename[0] == '/')
00180 full_filename = filename;
00181 else
00182 {
00183 size_t slash = _open_files.back().find_last_of("/");
00184 if (slash == string::npos)
00185 full_filename = filename;
00186 else
00187 full_filename = _open_files.back().substr(0, slash + 1) + filename;
00188 }
00189
00190 if (count(_open_files.begin(), _open_files.end(), full_filename) == 1)
00191 log_fatal(_("Recursive configuration file: %s"), full_filename.c_str());
00192
00193 ifstream file(full_filename.c_str());
00194 if (!file.is_open())
00195 log_fatal(_("Could not open file: %s"), full_filename.c_str());
00196
00197 size_t line_number = 0;
00198 try
00199 {
00200 _open_files.push_back(full_filename);
00201
00202 while (!file.eof())
00203 {
00204 string line;
00205 getline(file, line);
00206 line_number++;
00207
00208 if (line == "" || line[line.find_first_not_of(" \t")] == '#')
00209 continue;
00210
00211 _parse_argument(line);
00212 }
00213
00214 _open_files.pop_back();
00215 }
00216 catch (std::exception&)
00217 {
00218 file.close();
00219 log_error(_("From file: %s, line: %u"), full_filename.c_str(), line_number);
00220 throw;
00221 }
00222
00223 file.close();
00224 }
00225
00226 void core::add_module_option_value(const std::string& module_name,
00227 const std::string& option_name,
00228 const std::string& value)
00229 {
00230 log_debug(_("Setting option: module=%s option=%s value=%s"),
00231 module_name.c_str(), option_name.c_str(), value.c_str());
00232
00233 if (module_name == "")
00234 log_fatal(_("Invalid module name: %s"), module_name.c_str());
00235
00236
00237 if (module_name == "path" || module_name == "p")
00238 {
00239 if (option_name != "")
00240 {
00241 log_fatal(_("Invalid path option: %s.%s"), module_name.c_str(),
00242 option_name.c_str());
00243 }
00244
00245 if (value == "")
00246 log_fatal(_("Path option must have a value"));
00247
00248 _paths.insert(_paths.begin(), value);
00249 return;
00250 }
00251
00252
00253 if (module_name == "file" || module_name == "f")
00254 {
00255 if (option_name != "")
00256 {
00257 log_fatal(_("Invalid file option: %s.%s"), module_name.c_str(),
00258 option_name.c_str());
00259 }
00260
00261 if (value == "")
00262 log_fatal(_("File option must have a value"));
00263
00264 parse_file(value);
00265 return;
00266 }
00267
00268 if (option_name == "")
00269 {
00270 if (value == "")
00271 {
00272
00273 get_or_add_module(module_name);
00274 return;
00275 }
00276
00277
00278 aliases::iterator alias;
00279 for (alias = _aliases.begin(); alias != _aliases.end(); ++alias)
00280 {
00281 if (module::normalize_name(alias->first) ==
00282 module::normalize_name(module_name))
00283 {
00284 alias->second = value;
00285 break;
00286 }
00287 }
00288
00289 if (alias == _aliases.end())
00290 _aliases.insert(pair<string, string>(module_name, value));
00291
00292 log_info(_("Added module alias: %s=%s"), module_name.c_str(),
00293 value.c_str());
00294 return;
00295 }
00296
00297 get_or_add_module(module_name)._set_option_value(option_name, value);
00298 }
00299
00300 void core::set_signal_handlers(void)
00301 {
00302 if (global_kernel_core != NULL)
00303 log_fatal(_("Global kernel core already set for signal handling"));
00304
00305 log_info(_("Setting signal handlers"));
00306
00307 global_kernel_core = this;
00308
00309 struct sigaction signal_action;
00310 memset(&signal_action, 0, sizeof(struct sigaction));
00311 signal_action.sa_handler = SIG_IGN;
00312
00313 if (sigemptyset(&signal_action.sa_mask) == -1)
00314 log_fatal(_("Failed sigemptyset: %s:%d"), strerror(errno), errno);
00315
00316 if (sigaction(SIGPIPE, &signal_action, 0) == -1)
00317 log_fatal(_("Failed SIGPIPE sigaction: %s:%d"), strerror(errno), errno);
00318
00319 signal_action.sa_handler = global_signal_handler;
00320
00321 if (sigaction(SIGHUP, &signal_action, 0) == -1)
00322 log_fatal(_("Failed SIGHUP sigaction: %s:%d"), strerror(errno), errno);
00323
00324 if (sigaction(SIGINT, &signal_action, 0) == -1)
00325 log_fatal(_("Failed SIGINT sigaction: %s:%d"), strerror(errno), errno);
00326
00327 if (sigaction(SIGQUIT, &signal_action, 0) == -1)
00328 log_fatal(_("Failed SIGQUIT sigaction: %s:%d"), strerror(errno), errno);
00329
00330 if (sigaction(SIGTERM, &signal_action, 0) == -1)
00331 log_fatal(_("Failed SIGTERM sigaction: %s:%d"), strerror(errno), errno);
00332
00333 if (sigaction(SIGUSR1, &signal_action, 0) == -1)
00334 log_fatal(_("Failed SIGUSR1 sigaction: %s:%d"), strerror(errno), errno);
00335
00336 if (sigaction(SIGUSR2, &signal_action, 0) == -1)
00337 log_fatal(_("Failed SIGUSR2 sigaction: %s:%d"), strerror(errno), errno);
00338 }
00339
00340 void core::handle_signal(int signal_number)
00341 {
00342 log_info(_("Caught signal: %d"), signal_number);
00343
00344 if (signal_number == SIGQUIT ||
00345 signal_number == SIGTERM ||
00346 signal_number == SIGINT)
00347 {
00348 shutdown();
00349 }
00350 }
00351
00352 module& core::get_or_add_module(const std::string& name)
00353 {
00354 const string& alias = _get_alias(name);
00355
00356 module* module = _get_module(alias);
00357 if (module != NULL)
00358 return *module;
00359
00360 auto_ptr<kernel::module> new_module(new kernel::module(*this, alias,
00361 _threshold));
00362 _new_modules.push_back(new_module.get());
00363 return *(new_module.release());
00364 }
00365
00366 module& core::get_module(const std::string& name) const
00367 {
00368 const string& alias = _get_alias(name);
00369
00370 module* module = _get_module(alias);
00371 if (module == NULL)
00372 log_fatal(_("Could not find module: %s"), alias.c_str());
00373
00374 return *module;
00375 }
00376
00377 size_t core::get_module_count(void) const
00378 {
00379 return _modules.size() + _new_modules.size();
00380 }
00381
00382 module* core::begin_module(void)
00383 {
00384 _module_iterator = _modules.begin();
00385 _iterator_on_modules = true;
00386 return next_module();
00387 }
00388
00389 module* core::next_module(void)
00390 {
00391 if (_iterator_on_modules && _module_iterator == _modules.end())
00392 {
00393 _module_iterator = _new_modules.begin();
00394 _iterator_on_modules = false;
00395 }
00396
00397 if (!_iterator_on_modules && _module_iterator == _new_modules.end())
00398 return NULL;
00399
00400 return *(_module_iterator++);
00401 }
00402
00403 void core::add_service(const std::string& name, service* service)
00404 {
00405 pair<services::iterator, bool> result;
00406 result = _services.insert(pair<string, kernel::service*>(name, service));
00407 if (result.second == false)
00408 log_fatal(_("Service already exists: %s"), name.c_str());
00409
00410 log_info(_("Set service: %s"), name.c_str());
00411 }
00412
00413 service* core::remove_service(const std::string& name)
00414 {
00415 services::iterator result = _services.find(name);
00416 if (result == _services.end())
00417 log_fatal(_("Could not find service: %s"), name.c_str());
00418
00419 service* service = result->second;
00420 _services.erase(result);
00421 log_info(_("Removed service: %s"), name.c_str());
00422 return service;
00423 }
00424
00425 service& core::get_service(const std::string& name) const
00426 {
00427 services::const_iterator result = _services.find(name);
00428 if (result == _services.end())
00429 log_fatal(_("Could not find service: %s"), name.c_str());
00430
00431 return *result->second;
00432 }
00433
00434 size_t core::get_service_count(void) const
00435 {
00436 return _services.size();
00437 }
00438
00439 void core::add_log(const std::string& name, log* log)
00440 {
00441 pair<logs::iterator, bool> result;
00442 result = _logs.insert(pair<string, kernel::log*>(name, log));
00443 if (result.second == false)
00444 log_fatal(_("Log already exists: %s"), name.c_str());
00445
00446 log_info(_("Set log: %s"), name.c_str());
00447 }
00448
00449 log* core::remove_log(const std::string& name)
00450 {
00451 logs::iterator result = _logs.find(name);
00452 if (result == _logs.end())
00453 log_fatal(_("Could not find log: %s"), name.c_str());
00454
00455 log* log = result->second;
00456 _logs.erase(result);
00457 log_info(_("Removed log: %s"), name.c_str());
00458 return log;
00459 }
00460
00461 log& core::get_log(const std::string& name) const
00462 {
00463 logs::const_iterator result = _logs.find(name);
00464 if (result == _logs.end())
00465 log_fatal(_("Could not find log: %s"), name.c_str());
00466
00467 return *result->second;
00468 }
00469
00470 size_t core::get_log_count(void) const
00471 {
00472 return _logs.size();
00473 }
00474
00475 void core::run(void)
00476 {
00477
00478 while (!_new_modules.empty())
00479 {
00480
00481
00482
00483
00484
00485 size_t count = _modules.size();
00486 _modules.resize(count + _new_modules.size());
00487 copy(_new_modules.begin(), _new_modules.end(), _modules.begin() + count);
00488 _new_modules.clear();
00489 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_load));
00490 }
00491
00492 if (_need_help)
00493 {
00494 _print_help();
00495 return;
00496 }
00497
00498
00499 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_check_options));
00500
00501 if (_need_config)
00502 {
00503 _print_config();
00504 return;
00505 }
00506
00507 if (_modules.empty())
00508 log_fatal(_("No modules found"));
00509
00510
00511 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_start));
00512
00513 log_notice(_("Core now running"));
00514
00515 char buffer[1024];
00516 while (!_shutdown_request)
00517 {
00518
00519 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_run));
00520 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_reconfigure));
00521 if (read(_notify_pipe[0], buffer, sizeof(buffer)) == -1 && errno != EINTR)
00522 log_fatal(_("Failed notify pipe read: %s:%d"), strerror(errno), errno);
00523 }
00524 }
00525
00526 void core::shutdown(void)
00527 {
00528 log_notice(_("Core received shutdown request"));
00529 _shutdown_request = true;
00530 _notify();
00531 }
00532
00533
00534
00535
00536
00537 void core::_parse_argument(std::string argument)
00538 {
00539 size_t module_offset = argument.find_first_not_of("-");
00540 if (module_offset > 0)
00541 argument.erase(0, module_offset);
00542
00543
00544 if (argument.find_first_not_of("v") == string::npos)
00545 return;
00546
00547
00548 if (argument == "help" || argument == "h")
00549 {
00550 _need_help = true;
00551 return;
00552 }
00553
00554
00555 if (argument == "config" || argument == "c")
00556 {
00557 _need_config = true;
00558 return;
00559 }
00560
00561
00562 size_t option_offset = argument.find(".");
00563 size_t value_offset = argument.find("=");
00564 if (option_offset > value_offset)
00565 option_offset = string::npos;
00566
00567 string module_name;
00568 if (option_offset == string::npos)
00569 {
00570 if (value_offset == string::npos)
00571 module_name = argument;
00572 else
00573 module_name = string(argument, 0, value_offset);
00574 }
00575 else
00576 module_name = string(argument, 0, option_offset);
00577
00578
00579 if (module_name == "v")
00580 return;
00581
00582 string option_name;
00583 if (option_offset != string::npos)
00584 {
00585 option_offset++;
00586 if (value_offset == string::npos)
00587 option_name = string(argument, option_offset);
00588 else
00589 {
00590 option_name = string(argument, option_offset,
00591 value_offset - option_offset);
00592 }
00593 }
00594
00595 string value;
00596 if (value_offset != string::npos)
00597 value = string(argument, value_offset + 1);
00598
00599 add_module_option_value(module_name, option_name, value);
00600 }
00601
00602 const string& core::_get_alias(const std::string& name) const
00603 {
00604 for (aliases::const_iterator alias = _aliases.begin();
00605 alias != _aliases.end();
00606 ++alias)
00607 {
00608 if (module::normalize_name(alias->first) == module::normalize_name(name))
00609 return alias->second;
00610 }
00611
00612 return name;
00613 }
00614
00615 module* core::_get_module(const std::string& name) const
00616 {
00617
00618
00619
00620
00621
00622 for (modules::const_iterator module = _modules.begin();
00623 module != _modules.end();
00624 ++module)
00625 {
00626 if ((*module)->get_normalized_name() == module::normalize_name(name))
00627 return *module;
00628 }
00629
00630 for (modules::const_iterator module = _new_modules.begin();
00631 module != _new_modules.end();
00632 ++module)
00633 {
00634 if ((*module)->get_normalized_name() == module::normalize_name(name))
00635 return *module;
00636 }
00637
00638 return NULL;
00639 }
00640
00641 void core::_notify(void)
00642 {
00643 if (write(_notify_pipe[1], "\0", 1) == -1 && errno != EINTR)
00644 log_fatal(_("Failed notify pipe write: %s:%d"), strerror(errno), errno);
00645 }
00646
00647 void core::_set_fatal_message(const char* format, std::va_list arguments) const
00648 {
00649 char message[SCALESTACK_MAX_MESSAGE_SIZE];
00650 vsnprintf(message, SCALESTACK_MAX_MESSAGE_SIZE, format, arguments);
00651 throw kernel::exception("kernel", message);
00652 }
00653
00654 void core::_log_message(log::level log_level,
00655 const char* format,
00656 std::va_list arguments) const
00657 {
00658 _log(log_level, "kernel", format, arguments);
00659 }
00660
00661 void core::_log(log::level log_level,
00662 const char* context,
00663 const char* format,
00664 std::va_list arguments) const
00665 {
00666 char message[SCALESTACK_MAX_MESSAGE_SIZE];
00667 vsnprintf(message, SCALESTACK_MAX_MESSAGE_SIZE, format, arguments);
00668
00669 for (logs::const_iterator log = _logs.begin(); log != _logs.end(); ++log)
00670 log->second->write_log(log_level, context, message);
00671
00672 if (log_level == log::LEVEL_FATAL)
00673 throw kernel::exception(context, message);
00674 }
00675
00676 void core::_print_help(void)
00677 {
00678 cout << endl << PACKAGE_STRING << endl << _("\n\
00679 kernel\n\
00680 v - Increase kernel log verbosity threshold by one.\n\
00681 v=THRESHOLD - Set kernel log verbosity threshold to THRESHOLD.\n\
00682 h, help - Display this help message and exit.\n\
00683 c, config - Print configuration out and exit after parsing all options.\n\
00684 f, file=FILE - Read FILE for configuration options to parse.\n\
00685 p, path=PATH - Add PATH to the module directory search list.\n\
00686 (Default: ") <<
00687 SCALESTACK_QUOTE_VALUE(SCALESTACK_MODULE_PATH) << ")\n\
00688 \n";
00689
00690 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_print_help));
00691
00692 cout << _("\n\
00693 Modules can be loaded by simply giving the module name as an option. For\n\
00694 example, if you run 'scalestack echo::server::tcp', this will load the TCP\n\
00695 echo server module and any dependencies.\n\
00696 \n\
00697 Module aliases may be specified using the format:\n\
00698 \n\
00699 module_alias=module_name\n\
00700 \n\
00701 For example, if you run 'scalestack event::service=event::libevent', the\n\
00702 module 'event::libevent' will be loaded if any other modules depend on\n\
00703 'event::service'. This allows a generic service name to be listed as a\n\
00704 dependency when there are multiple modules that can provide that service.\n\
00705 \n\
00706 Module options are specified using the format\n\
00707 \n\
00708 module_name.option[=value]\n\
00709 \n\
00710 For example, if you run 'scalestack echo::server::tcp.addresses=:4321', the\n\
00711 echo::server::tcp module will be loaded and will be run with a listening\n\
00712 socket bound to port '4321'. For boolean options, you can specify\n\
00713 'false', 'f', 'no', 'n', or '0' to mean false using any mix of upper and\n\
00714 lower case. Everything else will be treated as true.\n\
00715 \n");
00716 }
00717
00718 void core::_print_config(void)
00719 {
00720 cout << "v=" << _threshold << endl;
00721 for (paths::const_iterator path = _paths.begin();
00722 path != _paths.end();
00723 ++path)
00724 {
00725 cout << "path=" << *path << endl;
00726 }
00727
00728 aliases::const_iterator alias;
00729 for (alias = _aliases.begin(); alias != _aliases.end(); ++alias)
00730 cout << alias->first << "=" << alias->second << endl;
00731
00732 for_each(_modules.begin(), _modules.end(), mem_fun(&module::_print_config));
00733 }
00734
00735 }
00736 }