blob: 572969fcb4c99334920d746d06f667b5892eb10f [file] [log] [blame]
// Copyright (c) 2010, 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <config.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <dbus-c++/dbus.h>
#include <dbus-c++/glib-integration.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include "src/cashew_server.h"
#include "src/service_manager.h"
namespace cashew {
static const int kMillisecondsPerSecond = 1000;
static const int kDBusConnectionTimeoutMilliseconds =
1 * kMillisecondsPerSecond;
typedef int Signal;
typedef void (*SignalHandler)(Signal signal);
int InstallSignalHandler(const Signal signal,
const SignalHandler signal_handler,
const sigset_t& mask) {
DLOG(INFO) << "installing handler for signal " << signal;
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = signal_handler;
action.sa_mask = mask;
return sigaction(signal, &action, NULL);
}
static DBus::Glib::BusDispatcher *dispatcher = NULL;
static GMainLoop *main_loop = NULL;
static CashewServer *server = NULL;
static ServiceManager *service_manager = NULL;
static void OnSignal(int signal) {
DLOG(INFO) << "received signal " << signal;
if (main_loop != NULL) {
// TODO(vlaviano): g_idle_add a callback to quit the main loop instead of
// doing it directly here to remove some low severity races
g_main_loop_quit(main_loop);
}
}
int InstallSignalHandlers() {
sigset_t mask;
if (sigemptyset(&mask) < 0) {
PLOG(ERROR) << "sigemptyset failed";
return -1;
}
if (sigaddset(&mask, SIGINT) < 0) {
PLOG(ERROR) << "couldn't add SIGINT to mask";
return -1;
}
if (sigaddset(&mask, SIGTERM) < 0) {
PLOG(ERROR) << "couldn't add SIGTERM to mask";
return -1;
}
if (InstallSignalHandler(SIGINT, OnSignal, mask) < 0) {
PLOG(ERROR) << "couldn't install SIGINT handler";
return -1;
}
if (InstallSignalHandler(SIGTERM, OnSignal, mask) < 0) {
PLOG(ERROR) << "couldn't install SIGTERM handler";
return -1;
}
return 0;
}
// should not be called while event loop is running
static void CleanUpForExit() {
DCHECK(main_loop == NULL || !g_main_loop_is_running(main_loop));
DLOG(INFO) << "cleaning up";
delete server;
server = NULL;
delete service_manager;
service_manager = NULL;
DBus::default_dispatcher = NULL;
delete dispatcher;
dispatcher = NULL;
if (main_loop != NULL) {
g_main_loop_unref(main_loop);
main_loop = NULL;
}
google::ShutdownGoogleLogging();
}
} // namespace cashew
int main(int argc, char *argv[]) {
google::SetUsageMessage(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler();
LOG(INFO) << PACKAGE_STRING;
DLOG(INFO) << "creating main loop";
cashew::main_loop = g_main_loop_new(NULL, false);
if (cashew::main_loop == NULL) {
LOG(ERROR) << "couldn't create main loop";
cashew::CleanUpForExit();
exit(EXIT_FAILURE);
}
DLOG(INFO) << "creating dbus dispatcher";
cashew::dispatcher = new(std::nothrow) DBus::Glib::BusDispatcher();
if (cashew::dispatcher == NULL) {
LOG(ERROR) << "couldn't create dbus dispatcher";
cashew::CleanUpForExit();
exit(EXIT_FAILURE);
}
DBus::default_dispatcher = cashew::dispatcher;
cashew::dispatcher->attach(NULL);
DLOG(INFO) << "creating service manager";
DBus::Connection client_conn = DBus::Connection::SystemBus();
client_conn.set_timeout(cashew::kDBusConnectionTimeoutMilliseconds);
cashew::service_manager = cashew::ServiceManager::NewServiceManager(
client_conn, cashew::main_loop);
if (cashew::service_manager == NULL) {
LOG(ERROR) << "couldn't create service manager";
cashew::CleanUpForExit();
exit(EXIT_FAILURE);
}
DLOG(INFO) << "creating cashew server";
// TODO(vlaviano): can we share a single conn for client and server roles?
DBus::Connection server_conn = DBus::Connection::SystemBus();
server_conn.request_name(cashew::CashewServer::kServiceName);
server_conn.set_timeout(cashew::kDBusConnectionTimeoutMilliseconds);
cashew::server = new(std::nothrow) cashew::CashewServer(server_conn,
cashew::service_manager, cashew::main_loop);
if (cashew::server == NULL) {
LOG(ERROR) << "couldn't create cashew server";
cashew::CleanUpForExit();
exit(EXIT_FAILURE);
}
if (cashew::InstallSignalHandlers() < 0) {
LOG(ERROR) << "couldn't install signal handlers";
cashew::CleanUpForExit();
exit(EXIT_FAILURE);
}
DLOG(INFO) << "entering event loop";
g_main_loop_run(cashew::main_loop);
DLOG(INFO) << "exited event loop";
cashew::CleanUpForExit();
exit(EXIT_SUCCESS);
}