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); }