Merge "buffet: Add a HACKING file"
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp
index 6b08e4c..d396525 100644
--- a/buffet/buffet.gyp
+++ b/buffet/buffet.gyp
@@ -35,9 +35,12 @@
'sources': [
'data_encoding.cc',
'dbus_manager.cc',
+ 'dbus_constants.cc',
+ 'dbus_utils.cc',
'http_request.cc',
'http_transport_curl.cc',
'http_utils.cc',
+ 'manager.cc',
'mime_utils.cc',
'string_utils.cc',
],
@@ -57,6 +60,7 @@
'type': 'executable',
'sources': [
'buffet_client.cc',
+ 'dbus_constants.cc',
],
},
{
diff --git a/buffet/buffet_client.cc b/buffet/buffet_client.cc
index 83d5f9c..9568834 100755
--- a/buffet/buffet_client.cc
+++ b/buffet/buffet_client.cc
@@ -2,55 +2,148 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <iostream>
#include <string>
#include <base/logging.h>
#include <base/memory/scoped_ptr.h>
#include <dbus/bus.h>
#include <dbus/object_proxy.h>
-#include <gflags/gflags.h>
+#include <dbus/message.h>
+#include "buffet/dbus_constants.h"
#include "buffet/dbus_manager.h"
-DEFINE_bool(testmethod, false, "Call the Buffet Test Method.");
+using namespace buffet::dbus_constants;
namespace {
-dbus::ObjectProxy* GetBuffetDBusProxy(dbus::Bus *bus) {
+dbus::ObjectProxy* GetBuffetDBusProxy(dbus::Bus *bus,
+ const std::string& object_path) {
return bus->GetObjectProxy(
- buffet::kBuffetServiceName,
- dbus::ObjectPath(buffet::kBuffetServicePath));
+ buffet::dbus_constants::kServiceName,
+ dbus::ObjectPath(object_path));
}
-void CallTestMethod(dbus::ObjectProxy* proxy) {
+bool CallTestMethod(dbus::ObjectProxy* proxy) {
int timeout_ms = 1000;
- dbus::MethodCall method_call(buffet::kBuffetInterface,
- buffet::kTestMethod);
+ dbus::MethodCall method_call(buffet::dbus_constants::kRootInterface,
+ buffet::dbus_constants::kRootTestMethod);
scoped_ptr<dbus::Response> response(proxy->CallMethodAndBlock(&method_call,
timeout_ms));
if (!response) {
- LOG(ERROR) << "Failed to receive a response.";
- return;
- } else {
- LOG(INFO) << "Received a response.";
+ std::cout << "Failed to receive a response." << std::endl;
+ return false;
}
+ std::cout << "Received a response." << std::endl;
+ return true;
}
-} // end namespace
-
-int main(int argc, char** argv) {
- google::ParseCommandLineFlags(&argc, &argv, true);
-
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SYSTEM;
- scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
-
- auto proxy = GetBuffetDBusProxy(bus);
- if (FLAGS_testmethod) {
- CallTestMethod(proxy);
+bool CallManagerRegisterDevice(dbus::ObjectProxy* proxy,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const std::string& api_key) {
+ dbus::MethodCall method_call(
+ buffet::dbus_constants::kManagerInterface,
+ buffet::dbus_constants::kManagerRegisterDeviceMethod);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(client_id);
+ writer.AppendString(client_secret);
+ writer.AppendString(api_key);
+ int timeout_ms = 1000;
+ scoped_ptr<dbus::Response> response(
+ proxy->CallMethodAndBlock(&method_call, timeout_ms));
+ if (!response) {
+ std::cout << "Failed to receive a response." << std::endl;
+ return false;
}
- LOG(INFO) << "Done.";
- return 0;
+ dbus::MessageReader reader(response.get());
+ std::string registration_id;
+ if (!reader.PopString(®istration_id)) {
+ std::cout << "No registration id in response." << std::endl;
+ return false;
+ }
+
+ std::cout << "Registration ID is " << registration_id << std::endl;
+ return true;
+}
+
+bool CallManagerUpdateState(dbus::ObjectProxy* proxy,
+ const std::string& json_blob) {
+ dbus::MethodCall method_call(
+ buffet::dbus_constants::kManagerInterface,
+ buffet::dbus_constants::kManagerUpdateStateMethod);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(json_blob);
+ int timeout_ms = 1000;
+ scoped_ptr<dbus::Response> response(
+ proxy->CallMethodAndBlock(&method_call, timeout_ms));
+ if (!response) {
+ std::cout << "Failed to receive a response." << std::endl;
+ return false;
+ }
+ return true;
+}
+
+void usage() {
+ std::cerr << "Possible commands:" << std::endl;
+ std::cerr << " " << kRootTestMethod << std::endl;
+ std::cerr << " " << kManagerRegisterDeviceMethod
+ << " " << " <client id> <client secret> <api key>" << std::endl;
+ std::cerr << " " << kManagerUpdateStateMethod << std::endl;
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
+
+ if (argc < 2) {
+ usage();
+ return -1;
+ }
+
+ char* command = argv[1];
+ bool success = false;
+ if (strcmp(command, kRootTestMethod) == 0) {
+ auto proxy = GetBuffetDBusProxy(
+ bus, buffet::dbus_constants::kRootServicePath);
+ success = CallTestMethod(proxy);
+ } else if (strcmp(command, kManagerRegisterDeviceMethod) == 0) {
+ if (argc != 5) {
+ std::cerr << "Invalid number of arguments for "
+ << "Manager.RegisterDevice" << std::endl;
+ usage();
+ return -1;
+ }
+ auto proxy = GetBuffetDBusProxy(
+ bus, buffet::dbus_constants::kManagerServicePath);
+ success = CallManagerRegisterDevice(proxy, argv[2], argv[3], argv[4]);
+ } else if (strcmp(command, kManagerUpdateStateMethod) == 0) {
+ if (argc != 3) {
+ std::cerr << "Invalid number of arguments for "
+ << "Manager.UpdateState" << std::endl;
+ usage();
+ return -1;
+ }
+ auto proxy = GetBuffetDBusProxy(
+ bus, buffet::dbus_constants::kManagerServicePath);
+ success = CallManagerUpdateState(proxy, argv[2]);
+ } else {
+ std::cerr << "Unkown command: " << command << std::endl;
+ usage();
+ return -1;
+ }
+
+ if (success) {
+ std::cout << "Done." << std::endl;
+ return 0;
+ }
+
+ std::cout << "Done, with errors." << std::endl;
+ return -1;
}
diff --git a/buffet/dbus_constants.cc b/buffet/dbus_constants.cc
new file mode 100644
index 0000000..746058e
--- /dev/null
+++ b/buffet/dbus_constants.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 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 "buffet/dbus_constants.h"
+
+namespace buffet {
+
+namespace dbus_constants {
+
+const char kServiceName[] = "org.chromium.Buffet";
+
+const char kRootInterface[] = "org.chromium.Buffet";
+const char kRootServicePath[] = "/org/chromium/Buffet";
+
+const char kRootTestMethod[] = "TestMethod";
+
+const char kManagerInterface[] = "org.chromium.Buffet.Manager";
+const char kManagerServicePath[] = "/org/chromium/Buffet/Manager";
+
+const char kManagerUpdateStateMethod[] = "UpdateState";
+const char kManagerRegisterDeviceMethod[] = "RegisterDevice";
+
+} // namespace dbus_constants
+
+} // namespace buffet
diff --git a/buffet/dbus_constants.h b/buffet/dbus_constants.h
new file mode 100644
index 0000000..e30fdde
--- /dev/null
+++ b/buffet/dbus_constants.h
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+#ifndef BUFFET_DBUS_CONSTANTS_H_
+#define BUFFET_DBUS_CONSTANTS_H_
+
+namespace buffet {
+
+namespace dbus_constants {
+
+// The service name claimed by the Buffet daemon.
+extern const char kServiceName[];
+
+// Interface implemented by the object at kRootServicePath.
+extern const char kRootInterface[];
+extern const char kRootServicePath[];
+
+// Methods exposed as part of kRootInterface.
+extern const char kRootTestMethod[];
+
+// Interface implemented by the object at kManagerServicePath.
+extern const char kManagerInterface[];
+extern const char kManagerServicePath[];
+
+// Methods exposed as part of kManagerInterface.
+extern const char kManagerUpdateStateMethod[];
+extern const char kManagerRegisterDeviceMethod[];
+
+} // namespace dbus_constants
+
+} // namespace buffet
+
+#endif // BUFFET_DBUS_CONSTANTS_H_
diff --git a/buffet/dbus_manager.cc b/buffet/dbus_manager.cc
index c6031fc..ceddee1 100644
--- a/buffet/dbus_manager.cc
+++ b/buffet/dbus_manager.cc
@@ -8,6 +8,10 @@
#include <base/bind.h>
+#include "buffet/dbus_constants.h"
+
+using ::std::string;
+
namespace buffet {
namespace {
@@ -29,8 +33,7 @@
} // namespace
DBusManager::DBusManager()
- : bus_(nullptr),
- buffet_dbus_object_(nullptr) {}
+ : bus_(nullptr) {}
DBusManager::~DBusManager() {}
@@ -49,26 +52,36 @@
bus_ = new dbus::Bus(options);
CHECK(bus_->Connect());
- buffet_dbus_object_ = bus_->GetExportedObject(
- dbus::ObjectPath(kBuffetServicePath));
- ExportDBusMethod(kTestMethod, &DBusManager::HandleTestMethod);
+ // buffet_dbus_object is owned by the Bus.
+ auto buffet_dbus_object = GetExportedObject(dbus_constants::kRootServicePath);
+ ExportDBusMethod(
+ buffet_dbus_object,
+ dbus_constants::kRootInterface, dbus_constants::kRootTestMethod,
+ base::Bind(&DBusManager::HandleTestMethod, base::Unretained(this)));
- CHECK(bus_->RequestOwnershipAndBlock(kBuffetServiceName,
+ CHECK(bus_->RequestOwnershipAndBlock(dbus_constants::kServiceName,
dbus::Bus::REQUIRE_PRIMARY))
- << "Unable to take ownership of " << kBuffetServiceName;
+ << "Unable to take ownership of " << dbus_constants::kServiceName;
}
void DBusManager::ShutDownDBus() {
bus_->ShutdownAndBlock();
}
-void DBusManager::ExportDBusMethod(const std::string& method_name,
- DBusMethodCallMemberFunction member) {
- DCHECK(buffet_dbus_object_);
- CHECK(buffet_dbus_object_->ExportMethodAndBlock(
- kBuffetInterface, method_name,
- base::Bind(&HandleSynchronousDBusMethodCall,
- base::Bind(member, base::Unretained(this)))));
+dbus::ExportedObject* DBusManager::GetExportedObject(
+ const string& object_path) {
+ return bus_->GetExportedObject(dbus::ObjectPath(object_path));
+}
+
+void DBusManager::ExportDBusMethod(
+ dbus::ExportedObject* exported_object,
+ const string& interface_name,
+ const string& method_name,
+ base::Callback<scoped_ptr<dbus::Response>(dbus::MethodCall*)> handler) {
+ DCHECK(exported_object);
+ CHECK(exported_object->ExportMethodAndBlock(
+ interface_name, method_name,
+ base::Bind(&HandleSynchronousDBusMethodCall, handler)));
}
scoped_ptr<dbus::Response> DBusManager::HandleTestMethod(
diff --git a/buffet/dbus_manager.h b/buffet/dbus_manager.h
index da91391..a990ead 100644
--- a/buffet/dbus_manager.h
+++ b/buffet/dbus_manager.h
@@ -14,21 +14,6 @@
namespace buffet {
-// TODO(sosa): Move to chromeos/system_api once we're ready.
-const char kBuffetInterface[] = "org.chromium.Buffet";
-const char kBuffetServicePath[] = "/org/chromium/Buffet";
-const char kBuffetServiceName[] = "org.chromium.Buffet";
-
-// Methods exposed by buffet.
-const char kTestMethod[] = "TestMethod";
-
-class DBusManager;
-
-// Pointer to a member function for handling D-Bus method calls. If an empty
-// scoped_ptr is returned, an empty (but successful) response will be sent.
-typedef scoped_ptr<dbus::Response> (DBusManager::*DBusMethodCallMemberFunction)(
- dbus::MethodCall*);
-
// Class that manages dbus interactions in buffet.
class DBusManager {
public:
@@ -38,20 +23,30 @@
void Init();
void Finalize();
+ // Get an object owned by the ::dbus::Bus object. This object
+ // has methods to export DBus facing methods.
+ ::dbus::ExportedObject* GetExportedObject(
+ const std::string& object_path);
+
+ // Exports |method_name| on |exported_object| and uses |member|
+ // to handle calls.
+ void ExportDBusMethod(
+ ::dbus::ExportedObject* exported_object,
+ const std::string& interface_name,
+ const std::string& method_name,
+ base::Callback<scoped_ptr<::dbus::Response>(
+ ::dbus::MethodCall*)> handler);
+
private:
// Connects to the D-Bus system bus and exports methods.
void InitDBus();
void ShutDownDBus();
- // Exports |method_name| and uses |member| to handle calls.
- void ExportDBusMethod(const std::string& method_name,
- DBusMethodCallMemberFunction member);
-
// Callbacks for handling D-Bus signals and method calls.
- scoped_ptr<dbus::Response> HandleTestMethod(dbus::MethodCall* method_call);
+ scoped_ptr<::dbus::Response> HandleTestMethod(
+ ::dbus::MethodCall* method_call);
- scoped_refptr<dbus::Bus> bus_;
- dbus::ExportedObject* buffet_dbus_object_; // weak; owned by |bus_|
+ scoped_refptr<::dbus::Bus> bus_;
DISALLOW_COPY_AND_ASSIGN(DBusManager);
};
diff --git a/buffet/dbus_utils.cc b/buffet/dbus_utils.cc
new file mode 100644
index 0000000..fcda628
--- /dev/null
+++ b/buffet/dbus_utils.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 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 <base/logging.h>
+
+#include "buffet/dbus_utils.h"
+
+namespace buffet {
+
+namespace dbus_utils {
+
+scoped_ptr<dbus::Response> GetBadArgsError(dbus::MethodCall* method_call,
+ const std::string& message) {
+ LOG(ERROR) << "Error while handling DBus call: " << message;
+ scoped_ptr<dbus::ErrorResponse> resp(dbus::ErrorResponse::FromMethodCall(
+ method_call, "org.freedesktop.DBus.Error.InvalidArgs", message));
+ return scoped_ptr<dbus::Response>(resp.release());
+}
+
+} // namespace dbus_utils
+
+} // namespace buffet
diff --git a/buffet/dbus_utils.h b/buffet/dbus_utils.h
new file mode 100644
index 0000000..dea6d02
--- /dev/null
+++ b/buffet/dbus_utils.h
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+#ifndef BUFFET_DBUS_UTILS_H_
+#define BUFFET_DBUS_UTILS_H_
+
+#include <string>
+
+#include <base/memory/scoped_ptr.h>
+#include <dbus/message.h>
+
+namespace buffet {
+
+namespace dbus_utils {
+
+scoped_ptr<dbus::Response> GetBadArgsError(dbus::MethodCall* method_call,
+ const std::string& message);
+
+} // namespace dbus_utils
+
+} // namespace buffet
+
+#endif // BUFFET_DBUS_UTILS_H_
+
diff --git a/buffet/main.cc b/buffet/main.cc
index 0b2e493..79843ab 100644
--- a/buffet/main.cc
+++ b/buffet/main.cc
@@ -15,6 +15,7 @@
#include <gflags/gflags.h>
#include "buffet/dbus_manager.h"
+#include "buffet/manager.h"
DEFINE_string(logsroot, "/var/log", "Root directory for buffet logs.");
@@ -79,8 +80,11 @@
// Initialize the dbus_manager.
buffet::DBusManager dbus_manager;
dbus_manager.Init();
-
- message_loop.Run();
+ {
+ // The Manager needs the dbus_manager to remain in scope for its lifetime.
+ buffet::Manager manager(&dbus_manager);
+ message_loop.Run();
+ }
dbus_manager.Finalize();
return 0;
diff --git a/buffet/manager.cc b/buffet/manager.cc
new file mode 100644
index 0000000..4daa9fc
--- /dev/null
+++ b/buffet/manager.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 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 "buffet/manager.h"
+
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+
+#include "buffet/dbus_constants.h"
+#include "buffet/dbus_manager.h"
+#include "buffet/dbus_utils.h"
+
+using buffet::dbus_utils::GetBadArgsError;
+
+namespace buffet {
+
+Manager::Manager(DBusManager* dbus_manager) : dbus_manager_(dbus_manager) {
+ dbus::ExportedObject* exported_object = dbus_manager_->GetExportedObject(
+ dbus_constants::kManagerServicePath);
+ dbus_manager_->ExportDBusMethod(exported_object,
+ dbus_constants::kManagerInterface,
+ dbus_constants::kManagerRegisterDeviceMethod,
+ base::Bind(&Manager::HandleRegisterDevice,
+ base::Unretained(this)));
+ dbus_manager_->ExportDBusMethod(exported_object,
+ dbus_constants::kManagerInterface,
+ dbus_constants::kManagerUpdateStateMethod,
+ base::Bind(&Manager::HandleUpdateState,
+ base::Unretained(this)));
+}
+
+Manager::~Manager() {
+ // Unregister ourselves from the Bus. This prevents the bus from calling
+ // our callbacks in between the Manager's death and the bus unregistering
+ // our exported object on shutdown. Unretained makes no promises of memory
+ // management.
+ auto exported_object = dbus_manager_->GetExportedObject(
+ dbus_constants::kManagerServicePath);
+ exported_object->Unregister();
+}
+
+scoped_ptr<dbus::Response> Manager::HandleRegisterDevice(
+ dbus::MethodCall* method_call) {
+ // Read the parameters to the method.
+ dbus::MessageReader reader(method_call);
+ if (!reader.HasMoreData()) {
+ return GetBadArgsError(method_call, "No parameters to RegisterDevice");
+ }
+ std::string client_id, client_secret, api_key;
+ if (!reader.PopString(&client_id)) {
+ return GetBadArgsError(method_call, "Failed to read client_id");
+ }
+ if (!reader.PopString(&client_secret)) {
+ return GetBadArgsError(method_call, "Failed to read client_secret");
+ }
+ if (!reader.PopString(&api_key)) {
+ return GetBadArgsError(method_call, "Failed to read api_key");
+ }
+ if (reader.HasMoreData()) {
+ return GetBadArgsError(
+ method_call, "Too many parameters to RegisterDevice");
+ }
+
+ LOG(INFO) << "Received call to Manager.RegisterDevice()";
+ // TODO(wiley): Do something with these parameters to register the device.
+
+ // Send back our response.
+ scoped_ptr<dbus::Response> response(
+ dbus::Response::FromMethodCall(method_call));
+ dbus::MessageWriter writer(response.get());
+ writer.AppendString("<registration ticket id>");
+ return response.Pass();
+}
+
+scoped_ptr<dbus::Response> Manager::HandleUpdateState(
+ dbus::MethodCall *method_call) {
+ // Read the parameters to the method.
+ dbus::MessageReader reader(method_call);
+ if (!reader.HasMoreData()) {
+ return GetBadArgsError(method_call, "No parameters to UpdateState");
+ }
+ std::string json_state_fragment;
+ if (!reader.PopString(&json_state_fragment)) {
+ return GetBadArgsError(method_call, "Failed to read json_state_fragment");
+ }
+ if (reader.HasMoreData()) {
+ return GetBadArgsError(method_call, "Too many parameters to UpdateState");
+ }
+
+ LOG(INFO) << "Received call to Manager.UpdateState()";
+ // TODO(wiley): Do something with these parameters to update state.
+
+ // Send back our response.
+ return dbus::Response::FromMethodCall(method_call);
+}
+
+} // namespace buffet
diff --git a/buffet/manager.h b/buffet/manager.h
new file mode 100644
index 0000000..d373a5e
--- /dev/null
+++ b/buffet/manager.h
@@ -0,0 +1,39 @@
+// Copyright 2014 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.
+
+#ifndef BUFFET_MANAGER_H_
+#define BUFFET_MANAGER_H_
+
+#include <base/basictypes.h>
+#include <base/memory/scoped_ptr.h>
+#include <dbus/message.h>
+
+namespace buffet {
+
+class DBusManager;
+
+// The Manager is responsible for global state of Buffet. It exposes
+// interfaces which affect the entire device such as device registration and
+// device state.
+class Manager {
+ public:
+ Manager(DBusManager* dbus_manager);
+ ~Manager();
+
+ private:
+ // Handles calls to org.chromium.Buffet.Manager.RegisterDevice().
+ scoped_ptr<dbus::Response> HandleRegisterDevice(
+ dbus::MethodCall* method_call);
+ // Handles calls to org.chromium.Buffet.Manager.UpdateState().
+ scoped_ptr<dbus::Response> HandleUpdateState(
+ dbus::MethodCall* method_call);
+
+ DBusManager* dbus_manager_; // Weak; DBusManager should outlive Manager.
+
+ DISALLOW_COPY_AND_ASSIGN(Manager);
+};
+
+} // namespace buffet
+
+#endif // BUFFET_MANAGER_H_