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_