void LocationsMgr::add_location( const std::string& name , const CfgPairs& cfg ) { try { if( cfg.at("type") == "szbase" ) add_szbase( name , cfg ); else if( cfg.at("type") == "proxy" ) add_proxy( name , cfg ); else throw invalid_value("Invalid 'type' in section " + name ); } catch( std::out_of_range& e ) { throw missing_option("Missing option in section " + name ); } }
void LocationsMgr::add_szbase( const std::string& name , const CfgPairs& cfg ) { auto draw_name = cfg.count("draw_name") ? cfg.at("draw_name") : name; try { auto& vars = vars_cache.get_szarp( cfg.at("base") ); loc_factory.register_location<SzbaseLocation>( name , draw_name , "szbase" , std::ref(vars) ); } catch( file_not_found_error& e ) { throw invalid_value( e.what() ); } catch( xml_parse_error& e ) { throw invalid_value( e.what() ); } }
void LocationsMgr::add_proxy( const std::string& name , const CfgPairs& cfg ) { unsigned port; try { port = boost::lexical_cast<unsigned>(cfg.at("port")); } catch( boost::bad_lexical_cast& e ) { throw invalid_value("Invalid port number in section " + name ); } catch( std::out_of_range& e ) { port = 9002; } auto draw_name = cfg.count("draw_name") ? cfg.at("draw_name") : ""; auto updater = std::make_shared <RemotesUpdater>( name , draw_name , cfg.at("address") , port , loc_factory ); updater->connect(); updaters[ name ] = updater; }
void LocationsMgr::add_szbase( const std::string& name , const CfgPairs& cfg ) { auto pa = cfg.count("prober_address") ? cfg.at("prober_address") : "127.0.0.1"; auto pp = cfg.count("prober_port") ? cfg.at("prober_port") : "8090"; auto draw_name = cfg.count("draw_name") ? cfg.at("draw_name") : name; unsigned p; try { p = boost::lexical_cast<unsigned>(pp); } catch( boost::bad_lexical_cast& e ) { throw invalid_value("Invalid port number in section " + name ); } try { auto& vars = vars_cache.get_szarp( cfg.at("base") ); loc_factory.register_location<SzbaseLocation>( name , draw_name , "szbase" , std::ref(vars) ); } catch( file_not_found_error& e ) { throw invalid_value( e.what() ); } catch( xml_parse_error& e ) { throw invalid_value( e.what() ); } }
int main( int argc , char** argv ) { srand(time(NULL)); po::options_description desc("Options"); desc.add_options() ("help,h", "Print this help messages") ("config_file", po::value<std::string>()->default_value(PREFIX "/iks/iks-server.ini"), "Custom configuration file.") ("no_daemon", "If specified server will not daemonize.") ("pid_file", po::value<std::string>(), "Specify destination of pid file that should be used. If not set no file is created.") ("log_level", po::value<unsigned>()->default_value(2), "Level how verbose should server be. Convention is: 0 - errors , 1 - warnings , 2 - info output , 3 and more - debug") ("name", po::value<std::string>()->default_value(ba::ip::host_name()), "Servers name -- defaults to hostname.") ("prefix,P", po::value<std::string>()->default_value(PREFIX), "Szarp prefix") ("port,p", po::value<unsigned>()->default_value(9002), "Server port on which we will listen"); po::variables_map vm; CfgPairs pairs; CfgPairs server_config; CfgSections locs_cfg; int ret_code = 0; std::string pid_path; try { po::store(po::parse_command_line(argc, argv, desc), vm); if( boost::filesystem::exists(vm["config_file"].as<std::string>()) ) { auto parsed = po::parse_config_file<char>(vm["config_file"].as<std::string>().c_str(), desc, true); for( const auto& o : parsed.options ) if( o.unregistered ) pairs[boost::erase_all_copy(o.string_key," ")] = o.value[0]; std::copy_if(pairs.begin(), pairs.end(), std::inserter(server_config, server_config.end()), [] (std::pair<std::string, std::string> p) { return p.first.find('.') == std::string::npos; }); locs_cfg.from_flat( pairs ); po::store(parsed,vm); } if ( vm.count("help") ) { std::cout << desc << std::endl; return 0; } po::notify(vm); } catch(po::error& e) { std::cerr << "Options parse error: " << e.what() << std::endl << std::endl; std::cerr << desc << std::endl; return 1; } const char* logname = vm.count("no_daemon") ? NULL : "iks-server" ; sz_loginit( vm["log_level"].as<unsigned>() , logname , SZ_LIBLOG_FACILITY_DAEMON ); sz_log(2,"Welcome, milord"); try { SzbaseWrapper::init( vm["prefix"].as<std::string>() ); boost::asio::io_service& io_service = GlobalService::get_service(); tcp::endpoint endpoint(tcp::v4(), vm["port"].as<unsigned>() ); TcpServer ts(io_service, endpoint); LocationsMgr lm; lm.add_locations( locs_cfg ); lm.add_config( server_config ); ts.on_connected ( bind(&LocationsMgr::on_new_connection,&lm,p::_1) ); ts.on_disconnected( bind(&LocationsMgr::on_disconnected ,&lm,p::_1) ); ba::signal_set signals(io_service, SIGINT, SIGTERM); signals.async_wait( bind(&ba::io_service::stop, &io_service) ); /** * Check if pid file can be written before daemonizing * and write current pid. */ if( vm.count("pid_file") ) { pid_path = vm["pid_file"].as<std::string>(); if( boost::filesystem::exists( pid_path ) ) { pid_path.clear(); /** prevent from removing not our pidfile */ throw init_error("pid file " + pid_path + " already exists"); } std::ofstream pf( vm["pid_file"].as<std::string>() ); pf << get_pid(); } /** * Daemonize */ if( !vm.count("no_daemon") ) if( !daemonize( io_service ) ) throw init_error("Cannot become proper daemon"); /** * Write new pid after daemonizing */ if( !pid_path.empty() && !vm.count("no_daemon") ) { std::ofstream pf( pid_path , std::ofstream::trunc ); pf << get_pid(); } sz_log(2,"Start serving on port %d", vm["port"].as<unsigned>() ); io_service.run(); } catch( std::exception& e ) { sz_log(0,"Exception occurred: %s" , e.what() ); ret_code = 1; /**< return error code */ } /** Remove pid file at exit */ if( !pid_path.empty() ) boost::filesystem::remove( pid_path ); /** * Quit with polite message */ switch( rand() % 23 ) { case 0 : sz_log(2 , "Au revoir"); break; case 1 : sz_log(2 , "Arrivederci"); break; case 2 : sz_log(2 , "Auf Wiedersehen"); break; case 3 : sz_log(2 , "See you later"); break; case 4 : sz_log(2 , "So long!"); break; default : sz_log(2 , "Goodbye"); break; } return ret_code; }