コード例 #1
0
ファイル: main.cpp プロジェクト: AiprNick/homestead
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(&registration_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);
}
コード例 #2
0
ファイル: main.cpp プロジェクト: ClearwaterCore/memento
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);
}
コード例 #3
0
ファイル: main.cpp プロジェクト: Metaswitch/memento
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);
}