int main(int argc, char**argv) { CommunicationMonitor* hss_comm_monitor = NULL; CommunicationMonitor* cassandra_comm_monitor = NULL; // Set up our exception signal handler for asserts and segfaults. signal(SIGABRT, signal_handler); signal(SIGSEGV, signal_handler); sem_init(&term_sem, 0, 0); signal(SIGTERM, terminate_handler); struct options options; options.local_host = "127.0.0.1"; options.home_domain = "dest-realm.unknown"; options.diameter_conf = "homestead.conf"; options.dns_servers.push_back("127.0.0.1"); options.http_address = "0.0.0.0"; options.http_port = 8888; options.http_threads = 1; options.cache_threads = 10; options.cassandra = "localhost"; options.dest_realm = ""; options.dest_host = "dest-host.unknown"; options.max_peers = 2; options.server_name = "sip:server-name.unknown"; options.scheme_unknown = "Unknown"; options.scheme_digest = "SIP Digest"; options.scheme_aka = "Digest-AKAv1-MD5"; options.access_log_enabled = false; options.impu_cache_ttl = 0; options.hss_reregistration_time = 1800; options.sprout_http_name = "sprout-http-name.unknown"; options.log_to_file = false; options.log_level = 0; options.sas_server = "0.0.0.0"; options.sas_system_name = ""; options.diameter_timeout_ms = 200; options.alarms_enabled = false; options.target_latency_us = 100000; options.max_tokens = 20; options.init_token_rate = 100.0; options.min_token_rate = 10.0; options.exception_max_ttl = 600; options.http_blacklist_duration = HttpResolver::DEFAULT_BLACKLIST_DURATION; options.diameter_blacklist_duration = DiameterResolver::DEFAULT_BLACKLIST_DURATION; boost::filesystem::path p = argv[0]; // Copy the filename to a string so that we can be sure of its lifespan - // the value passed to openlog must be valid for the duration of the program. std::string filename = p.filename().c_str(); openlog(filename.c_str(), PDLOG_PID, PDLOG_LOCAL6); CL_HOMESTEAD_STARTED.log(); if (init_logging_options(argc, argv, options) != 0) { closelog(); return 1; } Log::setLoggingLevel(options.log_level); if ((options.log_to_file) && (options.log_directory != "")) { // Work out the program name from argv[0], stripping anything before the final slash. char* prog_name = argv[0]; char* slash_ptr = rindex(argv[0], '/'); if (slash_ptr != NULL) { prog_name = slash_ptr + 1; } Log::setLogger(new Logger(options.log_directory, prog_name)); } TRC_STATUS("Log level set to %d", options.log_level); std::stringstream options_ss; for (int ii = 0; ii < argc; ii++) { options_ss << argv[ii]; options_ss << " "; } std::string options_str = "Command-line options were: " + options_ss.str(); TRC_INFO(options_str.c_str()); if (init_options(argc, argv, options) != 0) { closelog(); return 1; } AccessLogger* access_logger = NULL; if (options.access_log_enabled) { TRC_STATUS("Access logging enabled to %s", options.access_log_directory.c_str()); access_logger = new AccessLogger(options.access_log_directory); } // Create a DNS resolver and a SIP specific resolver. int af = AF_INET; struct in6_addr dummy_addr; if (inet_pton(AF_INET6, options.local_host.c_str(), &dummy_addr) == 1) { TRC_DEBUG("Local host is an IPv6 address"); af = AF_INET6; } SAS::init(options.sas_system_name, "homestead", SASEvent::CURRENT_RESOURCE_BUNDLE, options.sas_server, sas_write); // Set up the statistics (Homestead specific and Diameter) const static std::string known_stats[] = { "H_latency_us", "H_hss_latency_us", "H_hss_digest_latency_us", "H_hss_subscription_latency_us", "H_cache_latency_us", "H_incoming_requests", "H_rejected_overload", "H_diameter_invalid_dest_host", "H_diameter_invalid_dest_realm", }; const static int num_known_stats = sizeof(known_stats) / sizeof(std::string); LastValueCache* lvc = new LastValueCache(num_known_stats, known_stats, "homestead", 1000); StatisticsManager* stats_manager = new StatisticsManager(lvc); StatisticCounter* realm_counter = new StatisticCounter("H_diameter_invalid_dest_realm", lvc); StatisticCounter* host_counter = new StatisticCounter("H_diameter_invalid_dest_host", lvc); if (options.alarms_enabled) { // Create Homesteads's alarm objects. Note that the alarm identifier strings must match those // in the alarm definition JSON file exactly. hss_comm_monitor = new CommunicationMonitor(new Alarm("homestead", AlarmDef::HOMESTEAD_HSS_COMM_ERROR, AlarmDef::CRITICAL)); cassandra_comm_monitor = new CommunicationMonitor(new Alarm("homestead", AlarmDef::HOMESTEAD_CASSANDRA_COMM_ERROR, AlarmDef::CRITICAL)); // Start the alarm request agent AlarmReqAgent::get_instance().start(); AlarmState::clear_all("homestead"); } // Create an exception handler. The exception handler doesn't need // to quiesce the process before killing it. HealthChecker* hc = new HealthChecker(); pthread_t health_check_thread; pthread_create(&health_check_thread, NULL, &HealthChecker::static_main_thread_function, (void*)hc); exception_handler = new ExceptionHandler(options.exception_max_ttl, false, hc); LoadMonitor* load_monitor = new LoadMonitor(options.target_latency_us, options.max_tokens, options.init_token_rate, options.min_token_rate); DnsCachedResolver* dns_resolver = new DnsCachedResolver(options.dns_servers); HttpResolver* http_resolver = new HttpResolver(dns_resolver, af, options.http_blacklist_duration); Cache* cache = Cache::get_instance(); cache->configure_connection(options.cassandra, 9160, cassandra_comm_monitor); cache->configure_workers(exception_handler, options.cache_threads, 0); // Test the connection to Cassandra before starting the store. CassandraStore::ResultCode rc = cache->connection_test(); if (rc == CassandraStore::OK) { // Cassandra connection is good, so start the store. rc = cache->start(); } if (rc != CassandraStore::OK) { CL_HOMESTEAD_CASSANDRA_CACHE_INIT_FAIL.log(rc); closelog(); TRC_ERROR("Failed to initialize the Cassandra cache with error code %d.", rc); TRC_STATUS("Homestead is shutting down"); exit(2); } HttpConnection* http = new HttpConnection(options.sprout_http_name, false, http_resolver, SASEvent::HttpLogLevel::PROTOCOL, NULL); SproutConnection* sprout_conn = new SproutConnection(http); RegistrationTerminationTask::Config* rtr_config = NULL; PushProfileTask::Config* ppr_config = NULL; Diameter::SpawningHandler<RegistrationTerminationTask, RegistrationTerminationTask::Config>* rtr_task = NULL; Diameter::SpawningHandler<PushProfileTask, PushProfileTask::Config>* ppr_task = NULL; Cx::Dictionary* dict = NULL; Diameter::Stack* diameter_stack = Diameter::Stack::get_instance(); try { diameter_stack->initialize(); diameter_stack->configure(options.diameter_conf, exception_handler, hss_comm_monitor, realm_counter, host_counter); dict = new Cx::Dictionary(); rtr_config = new RegistrationTerminationTask::Config(cache, dict, sprout_conn, options.hss_reregistration_time); ppr_config = new PushProfileTask::Config(cache, dict, options.impu_cache_ttl, options.hss_reregistration_time); rtr_task = new Diameter::SpawningHandler<RegistrationTerminationTask, RegistrationTerminationTask::Config>(dict, rtr_config); ppr_task = new Diameter::SpawningHandler<PushProfileTask, PushProfileTask::Config>(dict, ppr_config); diameter_stack->advertize_application(Diameter::Dictionary::Application::AUTH, dict->TGPP, dict->CX); diameter_stack->register_handler(dict->CX, dict->REGISTRATION_TERMINATION_REQUEST, rtr_task); diameter_stack->register_handler(dict->CX, dict->PUSH_PROFILE_REQUEST, ppr_task); diameter_stack->register_fallback_handler(dict->CX); diameter_stack->start(); } catch (Diameter::Stack::Exception& e) { CL_HOMESTEAD_DIAMETER_INIT_FAIL.log(e._func, e._rc); closelog(); TRC_ERROR("Failed to initialize Diameter stack - function %s, rc %d", e._func, e._rc); TRC_STATUS("Homestead is shutting down"); exit(2); } HttpStack* http_stack = HttpStack::get_instance(); HssCacheTask::configure_diameter(diameter_stack, options.dest_realm.empty() ? options.home_domain : options.dest_realm, options.dest_host == "0.0.0.0" ? "" : options.dest_host, options.server_name, dict); HssCacheTask::configure_cache(cache); HssCacheTask::configure_health_checker(hc); HssCacheTask::configure_stats(stats_manager); // We should only query the cache for AV information if there is no HSS. If there is an HSS, we // should always hit it. If there is not, the AV information must have been provisioned in the // "cache" (which becomes persistent). bool hss_configured = !(options.dest_realm.empty() && (options.dest_host.empty() || options.dest_host == "0.0.0.0")); ImpiTask::Config impi_handler_config(hss_configured, options.impu_cache_ttl, options.scheme_unknown, options.scheme_digest, options.scheme_aka, options.diameter_timeout_ms); ImpiRegistrationStatusTask::Config registration_status_handler_config(hss_configured, options.diameter_timeout_ms); ImpuLocationInfoTask::Config location_info_handler_config(hss_configured, options.diameter_timeout_ms); ImpuRegDataTask::Config impu_handler_config(hss_configured, options.hss_reregistration_time, options.diameter_timeout_ms); ImpuIMSSubscriptionTask::Config impu_handler_config_old(hss_configured, options.hss_reregistration_time, options.diameter_timeout_ms); HttpStackUtils::PingHandler ping_handler; HttpStackUtils::SpawningHandler<ImpiDigestTask, ImpiTask::Config> impi_digest_handler(&impi_handler_config); HttpStackUtils::SpawningHandler<ImpiAvTask, ImpiTask::Config> impi_av_handler(&impi_handler_config); HttpStackUtils::SpawningHandler<ImpiRegistrationStatusTask, ImpiRegistrationStatusTask::Config> impi_reg_status_handler(®istration_status_handler_config); HttpStackUtils::SpawningHandler<ImpuLocationInfoTask, ImpuLocationInfoTask::Config> impu_loc_info_handler(&location_info_handler_config); HttpStackUtils::SpawningHandler<ImpuRegDataTask, ImpuRegDataTask::Config> impu_reg_data_handler(&impu_handler_config); HttpStackUtils::SpawningHandler<ImpuIMSSubscriptionTask, ImpuIMSSubscriptionTask::Config> impu_ims_sub_handler(&impu_handler_config_old); try { http_stack->initialize(); http_stack->configure(options.http_address, options.http_port, options.http_threads, exception_handler, access_logger, load_monitor, stats_manager); http_stack->register_handler("^/ping$", &ping_handler); http_stack->register_handler("^/impi/[^/]*/digest$", &impi_digest_handler); http_stack->register_handler("^/impi/[^/]*/av", &impi_av_handler); http_stack->register_handler("^/impi/[^/]*/registration-status$", &impi_reg_status_handler); http_stack->register_handler("^/impu/[^/]*/location$", &impu_loc_info_handler); http_stack->register_handler("^/impu/[^/]*/reg-data$", &impu_reg_data_handler); http_stack->register_handler("^/impu/", &impu_ims_sub_handler); http_stack->start(); } catch (HttpStack::Exception& e) { CL_HOMESTEAD_HTTP_INIT_FAIL.log(e._func, e._rc); closelog(); TRC_ERROR("Failed to initialize HttpStack stack - function %s, rc %d", e._func, e._rc); TRC_STATUS("Homestead is shutting down"); exit(2); } DiameterResolver* diameter_resolver = NULL; RealmManager* realm_manager = NULL; if (hss_configured) { diameter_resolver = new DiameterResolver(dns_resolver, af, options.diameter_blacklist_duration); realm_manager = new RealmManager(diameter_stack, options.dest_realm, options.dest_host, options.max_peers, diameter_resolver); realm_manager->start(); } TRC_STATUS("Start-up complete - wait for termination signal"); sem_wait(&term_sem); TRC_STATUS("Termination signal received - terminating"); CL_HOMESTEAD_ENDED.log(); try { http_stack->stop(); http_stack->wait_stopped(); } catch (HttpStack::Exception& e) { CL_HOMESTEAD_HTTP_STOP_FAIL.log(e._func, e._rc); TRC_ERROR("Failed to stop HttpStack stack - function %s, rc %d", e._func, e._rc); } cache->stop(); cache->wait_stopped(); try { diameter_stack->stop(); diameter_stack->wait_stopped(); } catch (Diameter::Stack::Exception& e) { CL_HOMESTEAD_DIAMETER_STOP_FAIL.log(e._func, e._rc); TRC_ERROR("Failed to stop Diameter stack - function %s, rc %d", e._func, e._rc); } delete dict; dict = NULL; delete ppr_config; ppr_config = NULL; delete rtr_config; rtr_config = NULL; delete ppr_task; ppr_task = NULL; delete rtr_task; rtr_task = NULL; delete sprout_conn; sprout_conn = NULL; if (hss_configured) { realm_manager->stop(); delete realm_manager; realm_manager = NULL; delete diameter_resolver; diameter_resolver = NULL; delete dns_resolver; dns_resolver = NULL; } delete realm_counter; realm_counter = NULL; delete host_counter; host_counter = NULL; delete stats_manager; stats_manager = NULL; delete lvc; lvc = NULL; hc->terminate(); pthread_join(health_check_thread, NULL); delete hc; hc = NULL; delete exception_handler; exception_handler = NULL; delete load_monitor; load_monitor = NULL; SAS::term(); closelog(); if (options.alarms_enabled) { // Stop the alarm request agent AlarmReqAgent::get_instance().stop(); // Delete Homestead's alarm objects delete hss_comm_monitor; delete cassandra_comm_monitor; } signal(SIGTERM, SIG_DFL); sem_destroy(&term_sem); }
int main(int argc, char**argv) { // Set up our exception signal handler for asserts and segfaults. signal(SIGABRT, signal_handler); signal(SIGSEGV, signal_handler); sem_init(&term_sem, 0, 0); signal(SIGTERM, terminate_handler); struct options options; options.local_host = "127.0.0.1"; options.http_address = "0.0.0.0"; options.http_port = 11888; options.http_threads = 1; options.http_worker_threads = 50; options.homestead_http_name = "homestead-http-name.unknown"; options.digest_timeout = 300; options.home_domain = "home.domain"; options.sas_server = "0.0.0.0"; options.sas_system_name = ""; options.access_log_enabled = false; options.log_to_file = false; options.log_level = 0; options.memcached_write_format = MemcachedWriteFormat::JSON; options.target_latency_us = 100000; options.max_tokens = 1000; options.init_token_rate = 100.0; options.min_token_rate = 10.0; options.exception_max_ttl = 600; options.http_blacklist_duration = HttpResolver::DEFAULT_BLACKLIST_DURATION; options.pidfile = ""; options.daemon = false; if (init_logging_options(argc, argv, options) != 0) { return 1; } Log::setLoggingLevel(options.log_level); if ((options.log_to_file) && (options.log_directory != "")) { // Work out the program name from argv[0], stripping anything before the final slash. char* prog_name = argv[0]; char* slash_ptr = rindex(argv[0], '/'); if (slash_ptr != NULL) { prog_name = slash_ptr + 1; } Log::setLogger(new Logger(options.log_directory, prog_name)); } TRC_STATUS("Log level set to %d", options.log_level); std::stringstream options_ss; for (int ii = 0; ii < argc; ii++) { options_ss << argv[ii]; options_ss << " "; } std::string options_str = "Command-line options were: " + options_ss.str(); TRC_INFO(options_str.c_str()); if (init_options(argc, argv, options) != 0) { return 1; } if (options.daemon) { // Options parsed and validated, time to demonize before writing out our // pidfile or spwaning threads. int errnum = Utils::daemonize(); if (errnum != 0) { TRC_ERROR("Failed to convert to daemon, %d (%s)", errnum, strerror(errnum)); exit(0); } } if (options.pidfile != "") { int rc = Utils::lock_and_write_pidfile(options.pidfile); if (rc == -1) { // Failure to acquire pidfile lock TRC_ERROR("Could not write pidfile - exiting"); return 2; } } start_signal_handlers(); AccessLogger* access_logger = NULL; if (options.access_log_enabled) { TRC_STATUS("Access logging enabled to %s", options.access_log_directory.c_str()); access_logger = new AccessLogger(options.access_log_directory); } HealthChecker* hc = new HealthChecker(); hc->start_thread(); // Create an exception handler. The exception handler doesn't need // to quiesce the process before killing it. exception_handler = new ExceptionHandler(options.exception_max_ttl, false, hc); SAS::init(options.sas_system_name, "memento", SASEvent::CURRENT_RESOURCE_BUNDLE, options.sas_server, sas_write, create_connection_in_management_namespace); // Ensure our random numbers are unpredictable. unsigned int seed; seed = time(NULL) ^ getpid(); srand(seed); // Create alarm and communication monitor objects for the conditions // reported by memento. CommunicationMonitor* mc_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_MEMCACHED_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Memcached"); Alarm* mc_vbucket_alarm = new Alarm("memento", AlarmDef::MEMENTO_MEMCACHED_VBUCKET_ERROR, AlarmDef::MAJOR); CommunicationMonitor* hs_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_HOMESTEAD_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Homestead"); CommunicationMonitor* cass_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_CASSANDRA_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Cassandra"); TRC_DEBUG("Starting alarm request agent"); AlarmReqAgent::get_instance().start(); MemcachedStore* m_store = new MemcachedStore(true, "./cluster_settings", mc_comm_monitor, mc_vbucket_alarm); AuthStore::SerializerDeserializer* serializer; std::vector<AuthStore::SerializerDeserializer*> deserializers; if (options.memcached_write_format == MemcachedWriteFormat::JSON) { serializer = new AuthStore::JsonSerializerDeserializer(); } else { serializer = new AuthStore::BinarySerializerDeserializer(); } deserializers.push_back(new AuthStore::JsonSerializerDeserializer()); deserializers.push_back(new AuthStore::BinarySerializerDeserializer()); AuthStore* auth_store = new AuthStore(m_store, serializer, deserializers, options.digest_timeout); LoadMonitor* load_monitor = new LoadMonitor(options.target_latency_us, options.max_tokens, options.init_token_rate, options.min_token_rate); LastValueCache* stats_aggregator = new MementoLVC(); // Create a DNS resolver and an HTTP specific resolver. int af = AF_INET; struct in6_addr dummy_addr; if (inet_pton(AF_INET6, options.local_host.c_str(), &dummy_addr) == 1) { TRC_DEBUG("Local host is an IPv6 address"); af = AF_INET6; } DnsCachedResolver* dns_resolver = new DnsCachedResolver("127.0.0.1"); HttpResolver* http_resolver = new HttpResolver(dns_resolver, af, options.http_blacklist_duration); HomesteadConnection* homestead_conn = new HomesteadConnection(options.homestead_http_name, http_resolver, load_monitor, hs_comm_monitor); // Create and start the call list store. CallListStore::Store* call_list_store = new CallListStore::Store(); call_list_store->configure_connection("localhost", 9160, cass_comm_monitor); // Test Cassandra connectivity. CassandraStore::ResultCode store_rc = call_list_store->connection_test(); if (store_rc == CassandraStore::OK) { // Store can connect to Cassandra, so start it. store_rc = call_list_store->start(); } if (store_rc != CassandraStore::OK) { TRC_ERROR("Unable to create call list store (RC = %d)", store_rc); exit(3); } HttpStack* http_stack = HttpStack::get_instance(); HttpStackUtils::SimpleStatsManager stats_manager(stats_aggregator); CallListTask::Config call_list_config(auth_store, homestead_conn, call_list_store, options.home_domain, stats_aggregator, hc, options.api_key); MementoSasLogger sas_logger; HttpStackUtils::PingHandler ping_handler; HttpStackUtils::SpawningHandler<CallListTask, CallListTask::Config> call_list_handler(&call_list_config, &sas_logger); HttpStackUtils::HandlerThreadPool pool(options.http_worker_threads, exception_handler); try { http_stack->initialize(); http_stack->configure(options.http_address, options.http_port, options.http_threads, exception_handler, access_logger, load_monitor, &stats_manager); http_stack->register_handler("^/ping$", &ping_handler); http_stack->register_handler("^/org.projectclearwater.call-list/users/[^/]*/call-list.xml$", pool.wrap(&call_list_handler)); http_stack->start(); } catch (HttpStack::Exception& e) { TRC_ERROR("Failed to initialize HttpStack stack - function %s, rc %d", e._func, e._rc); exit(2); } TRC_STATUS("Start-up complete - wait for termination signal"); sem_wait(&term_sem); TRC_STATUS("Termination signal received - terminating"); try { http_stack->stop(); http_stack->wait_stopped(); } catch (HttpStack::Exception& e) { TRC_ERROR("Failed to stop HttpStack stack - function %s, rc %d", e._func, e._rc); } call_list_store->stop(); call_list_store->wait_stopped(); hc->stop_thread(); delete homestead_conn; homestead_conn = NULL; delete call_list_store; call_list_store = NULL; delete http_resolver; http_resolver = NULL; delete dns_resolver; dns_resolver = NULL; delete load_monitor; load_monitor = NULL; delete auth_store; auth_store = NULL; delete call_list_store; call_list_store = NULL; delete m_store; m_store = NULL; delete exception_handler; exception_handler = NULL; delete hc; hc = NULL; // Stop the alarm request agent AlarmReqAgent::get_instance().stop(); delete mc_comm_monitor; mc_comm_monitor = NULL; delete mc_vbucket_alarm; mc_vbucket_alarm = NULL; delete hs_comm_monitor; hs_comm_monitor = NULL; delete cass_comm_monitor; cass_comm_monitor = NULL; SAS::term(); signal(SIGTERM, SIG_DFL); sem_destroy(&term_sem); }
int main(int argc, char**argv) { // Set up our exception signal handler for asserts and segfaults. signal(SIGABRT, signal_handler); signal(SIGSEGV, signal_handler); sem_init(&term_sem, 0, 0); signal(SIGTERM, terminate_handler); AstaireResolver* astaire_resolver = NULL; struct options options; options.local_host = "127.0.0.1"; options.http_address = "0.0.0.0"; options.http_port = 11888; options.http_threads = 1; options.http_worker_threads = 50; options.homestead_http_name = "homestead-http-name.unknown"; options.digest_timeout = 300; options.home_domain = "home.domain"; options.sas_system_name = ""; options.access_log_enabled = false; options.log_to_file = false; options.log_level = 0; options.astaire = ""; options.cassandra = ""; options.memcached_write_format = MemcachedWriteFormat::JSON; options.target_latency_us = 100000; options.max_tokens = 1000; options.init_token_rate = 100.0; options.min_token_rate = 10.0; options.min_token_rate = 0.0; options.exception_max_ttl = 600; options.astaire_blacklist_duration = AstaireResolver::DEFAULT_BLACKLIST_DURATION; options.http_blacklist_duration = HttpResolver::DEFAULT_BLACKLIST_DURATION; options.pidfile = ""; options.daemon = false; if (init_logging_options(argc, argv, options) != 0) { return 1; } Utils::daemon_log_setup(argc, argv, options.daemon, options.log_directory, options.log_level, options.log_to_file); std::stringstream options_ss; for (int ii = 0; ii < argc; ii++) { options_ss << argv[ii]; options_ss << " "; } std::string options_str = "Command-line options were: " + options_ss.str(); TRC_INFO(options_str.c_str()); if (init_options(argc, argv, options) != 0) { return 1; } if (options.pidfile != "") { int rc = Utils::lock_and_write_pidfile(options.pidfile); if (rc == -1) { // Failure to acquire pidfile lock TRC_ERROR("Could not write pidfile - exiting"); return 2; } } start_signal_handlers(); AccessLogger* access_logger = NULL; if (options.access_log_enabled) { TRC_STATUS("Access logging enabled to %s", options.access_log_directory.c_str()); access_logger = new AccessLogger(options.access_log_directory); } HealthChecker* hc = new HealthChecker(); hc->start_thread(); // Create an exception handler. The exception handler doesn't need // to quiesce the process before killing it. exception_handler = new ExceptionHandler(options.exception_max_ttl, false, hc); // Initialise the SasService, to read the SAS config to pass into SAS::Init SasService* sas_service = new SasService(options.sas_system_name, "memento", false); // Ensure our random numbers are unpredictable. unsigned int seed; seed = time(NULL) ^ getpid(); srand(seed); // Create a DNS resolver. int af = AF_INET; struct in6_addr dummy_addr; if (inet_pton(AF_INET6, options.local_host.c_str(), &dummy_addr) == 1) { TRC_DEBUG("Local host is an IPv6 address"); af = AF_INET6; } DnsCachedResolver* dns_resolver = new DnsCachedResolver("127.0.0.1"); // Create alarm and communication monitor objects for the conditions // reported by memento. AlarmManager* alarm_manager = new AlarmManager(); CommunicationMonitor* astaire_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager, "memento", AlarmDef::MEMENTO_ASTAIRE_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Astaire"); CommunicationMonitor* hs_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager, "memento", AlarmDef::MEMENTO_HOMESTEAD_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Homestead"); CommunicationMonitor* cass_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager, "memento", AlarmDef::MEMENTO_CASSANDRA_COMM_ERROR, AlarmDef::CRITICAL), "Memento", "Cassandra"); astaire_resolver = new AstaireResolver(dns_resolver, af, options.astaire_blacklist_duration); // Default the astaire hostname to the loopback IP if (options.astaire == "") { if (af == AF_INET6) { options.astaire = "[::1]"; } else { options.astaire = "127.0.0.1"; } } memcached_store = (Store*)new TopologyNeutralMemcachedStore(options.astaire, astaire_resolver, false, astaire_comm_monitor); AuthStore::SerializerDeserializer* serializer; std::vector<AuthStore::SerializerDeserializer*> deserializers; if (options.memcached_write_format == MemcachedWriteFormat::JSON) { serializer = new AuthStore::JsonSerializerDeserializer(); } else { serializer = new AuthStore::BinarySerializerDeserializer(); } deserializers.push_back(new AuthStore::JsonSerializerDeserializer()); deserializers.push_back(new AuthStore::BinarySerializerDeserializer()); AuthStore* auth_store = new AuthStore(memcached_store, serializer, deserializers, options.digest_timeout); LoadMonitor* load_monitor = new LoadMonitor(options.target_latency_us, options.max_tokens, options.init_token_rate, options.min_token_rate, options.max_token_rate); LastValueCache* stats_aggregator = new MementoLVC(); // Create a HTTP specific resolver. HttpResolver* http_resolver = new HttpResolver(dns_resolver, af, options.http_blacklist_duration); HttpClient* http_client = new HttpClient(false, http_resolver, nullptr, load_monitor, SASEvent::HttpLogLevel::PROTOCOL, hs_comm_monitor); HttpConnection* http_connection = new HttpConnection(options.homestead_http_name, http_client); HomesteadConnection* homestead_conn = new HomesteadConnection(http_connection); // Default to a 30s blacklist/graylist duration and port 9160 CassandraResolver* cass_resolver = new CassandraResolver(dns_resolver, af, 30, 30, 9160); // Default the cassandra hostname to the loopback IP if (options.cassandra == "") { if (af == AF_INET6) { options.cassandra = "[::1]"; } else { options.cassandra = "127.0.0.1"; } } // Create and start the call list store. CallListStore::Store* call_list_store = new CallListStore::Store(); call_list_store->configure_connection(options.cassandra, 9160, cass_comm_monitor, cass_resolver); // Test Cassandra connectivity. CassandraStore::ResultCode store_rc = call_list_store->connection_test(); if (store_rc == CassandraStore::OK) { // Store can connect to Cassandra, so start it. store_rc = call_list_store->start(); } if (store_rc != CassandraStore::OK) { TRC_ERROR("Unable to create call list store (RC = %d)", store_rc); exit(3); } HttpStackUtils::SimpleStatsManager stats_manager(stats_aggregator); HttpStack* http_stack = new HttpStack(options.http_threads, exception_handler, access_logger, load_monitor, &stats_manager); CallListTask::Config call_list_config(auth_store, homestead_conn, call_list_store, options.home_domain, stats_aggregator, hc, options.api_key); MementoSasLogger sas_logger; HttpStackUtils::PingHandler ping_handler; HttpStackUtils::SpawningHandler<CallListTask, CallListTask::Config> call_list_handler(&call_list_config, &sas_logger); HttpStackUtils::HandlerThreadPool pool(options.http_worker_threads, exception_handler); try { http_stack->initialize(); http_stack->bind_tcp_socket(options.http_address, options.http_port); http_stack->register_handler("^/ping$", &ping_handler); http_stack->register_handler("^/org.projectclearwater.call-list/users/[^/]*/call-list.xml$", pool.wrap(&call_list_handler)); http_stack->start(); } catch (HttpStack::Exception& e) { TRC_ERROR("Failed to initialize HttpStack stack - function %s, rc %d", e._func, e._rc); exit(2); } TRC_STATUS("Start-up complete - wait for termination signal"); sem_wait(&term_sem); TRC_STATUS("Termination signal received - terminating"); try { http_stack->stop(); http_stack->wait_stopped(); } catch (HttpStack::Exception& e) { TRC_ERROR("Failed to stop HttpStack stack - function %s, rc %d", e._func, e._rc); } call_list_store->stop(); call_list_store->wait_stopped(); hc->stop_thread(); delete homestead_conn; homestead_conn = NULL; delete http_connection; http_connection = NULL; delete http_client; http_client = NULL; delete call_list_store; call_list_store = NULL; delete http_resolver; http_resolver = NULL; delete cass_resolver; cass_resolver = NULL; delete dns_resolver; dns_resolver = NULL; delete load_monitor; load_monitor = NULL; delete auth_store; auth_store = NULL; delete call_list_store; call_list_store = NULL; delete astaire_resolver; astaire_resolver = NULL; delete memcached_store; memcached_store = NULL; delete exception_handler; exception_handler = NULL; delete hc; hc = NULL; delete http_stack; http_stack = NULL; delete astaire_comm_monitor; astaire_comm_monitor = NULL; delete hs_comm_monitor; hs_comm_monitor = NULL; delete cass_comm_monitor; cass_comm_monitor = NULL; delete alarm_manager; alarm_manager = NULL; delete sas_service; sas_service = NULL; signal(SIGTERM, SIG_DFL); sem_destroy(&term_sem); }