From f3c5a083b7248e73ff64dfb79a911870830650ff Mon Sep 17 00:00:00 2001 From: Daeheyon Jung Date: Thu, 30 Aug 2018 18:57:52 +0900 Subject: [PATCH] Add Send File Function Change-Id: I5765d48ad50e0aac545e0dd6a7660f6e6af0f8b1 Signed-off-by: Daeheyon Jung --- include/capability-manager_internal.h | 75 +++++++++++++ packaging/capi-appfw-capmgr.spec | 1 + src/client_internal.cc | 199 ++++++++++++++++++++++++++++++++++ src/dbus.cc | 87 +++++++++++++-- src/dbus.h | 3 + src/dbus_signal.h | 36 ++++++ tools/capmgr_test.cc | 91 ++++++++++++++-- 7 files changed, 472 insertions(+), 20 deletions(-) create mode 100755 include/capability-manager_internal.h create mode 100755 src/client_internal.cc mode change 100644 => 100755 src/dbus.cc mode change 100644 => 100755 src/dbus.h create mode 100755 src/dbus_signal.h mode change 100644 => 100755 tools/capmgr_test.cc diff --git a/include/capability-manager_internal.h b/include/capability-manager_internal.h new file mode 100755 index 0000000..ff3afdc --- /dev/null +++ b/include/capability-manager_internal.h @@ -0,0 +1,75 @@ +// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_ +#define INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_ + +#include "include/capability-manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct capmgr_file_s* capmgr_file_h; + +typedef int (*capmgr_file_finish_cb)(capmgr_file_h file, + int result, void* user_data); + +typedef int (*capmgr_file_progress_cb)( + capmgr_file_h file, int64_t sent_size, int64_t total_size, + void* user_data); + +/** + * @brief + */ +int capmgr_file_create(capmgr_file_h* file); + +/** + * @brief + */ +int capmgr_file_destroy(capmgr_file_h file); + +/** + * @brief + */ +int capmgr_file_set_device(capmgr_file_h file, + const capmgr_device_h device); + +/** + * @brief + */ +int capmgr_file_set_path(capmgr_file_h file, + const char* file_path); + +/** + * @brief + */ +int capmgr_file_set_finish_cb(capmgr_file_h file, + capmgr_file_finish_cb cb, void* user_data); + +/** + * @brief + */ +int capmgr_file_set_progress_cb(capmgr_file_h file, + capmgr_file_progress_cb cb, void* user_data); + +/** + * @brief + */ +int capmgr_file_send(capmgr_file_h file); + +/* TODO(darrenh.jung) +int capmgr_file_abort(capmgr_file_h file); + +int capmgr_file_cleanup(capmgr_file_h file); + +int capmgr_file_resume(capmgr_file_h file); +*/ + +#ifdef __cplusplus +} +#endif + +#endif // INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_ diff --git a/packaging/capi-appfw-capmgr.spec b/packaging/capi-appfw-capmgr.spec index b33eae0..37a2323 100644 --- a/packaging/capi-appfw-capmgr.spec +++ b/packaging/capi-appfw-capmgr.spec @@ -54,5 +54,6 @@ MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` %files devel %{_includedir}/capability-manager.h +%{_includedir}/capability-manager_internal.h %{_libdir}/pkgconfig/%{name}.pc %{_libdir}/lib%{name}.so diff --git a/src/client_internal.cc b/src/client_internal.cc new file mode 100755 index 0000000..c6ba05e --- /dev/null +++ b/src/client_internal.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#include + +#include +#include +#include +#include +#include + +#include "include/capability-manager.h" +#include "include/capability-manager_internal.h" +#include "src/dbus.h" +#include "src/dbus_signal.h" +#include "src/utils/logging.h" + +#define API __attribute__((visibility("default"))) + +struct capmgr_finish_cb_s { + int (*callback)(capmgr_file_h, int, void*); + void* user_data; +}; + +struct capmgr_progress_cb_s { + int (*callback)(capmgr_file_h, int64_t, int64_t, void*); + void* user_data; +}; + +struct capmgr_file_s { + capmgr_device_h device; + char* path; + capmgr::DBusSignal* ds; + capmgr_finish_cb_s finish_cb; + capmgr_progress_cb_s progress_cb; +}; + +int __default_finish_cb(capmgr_file_h file, int result, void *user_data) { + LOG(DEBUG) << "finished with: " << result; + return 0; +} + +int __default_progress_cb(capmgr_file_h file, int64_t sent_size, + int64_t total_size, void *user_data) { + LOG(DEBUG) << "progress: " << sent_size << "/" << total_size; + return 0; +} + +API int capmgr_file_create(capmgr_file_h* file) { + if (!file) + return CAPMGR_ERROR_INVALID_PARAMETER; + + try { + capmgr_file_s* f = new capmgr_file_s(); + capmgr_file_set_finish_cb(f, __default_finish_cb, nullptr); + capmgr_file_set_progress_cb(f, __default_progress_cb, nullptr); + + *file = f; + } catch (const std::bad_alloc& e) { + LOG(ERROR) << e.what(); + return CAPMGR_ERROR_OUT_OF_MEMORY; + } + + return CAPMGR_ERROR_NONE; +} + +API int capmgr_file_destroy(capmgr_file_h file) { + if (!file) + return CAPMGR_ERROR_INVALID_PARAMETER; + + capmgr_device_destroy(file->device); + free(file->path); + delete file->ds; + delete file; + + return CAPMGR_ERROR_NONE; +} + +API int capmgr_file_set_device(capmgr_file_h file, + const capmgr_device_h device) { + if (!file || !device) + return CAPMGR_ERROR_INVALID_PARAMETER; + + if (file->device) + capmgr_device_destroy(file->device); + + int ret = capmgr_device_clone(device, &file->device); + if (ret != CAPMGR_ERROR_NONE) + return CAPMGR_ERROR_OUT_OF_MEMORY; + + return CAPMGR_ERROR_NONE; +} + +API int capmgr_file_set_path(capmgr_file_h file, + const char* path) { + if (!file || !path) + return CAPMGR_ERROR_INVALID_PARAMETER; + + if (file->path) + free(file->path); + + file->path = strdup(path); + if (!file->path) + return CAPMGR_ERROR_OUT_OF_MEMORY; + + return CAPMGR_ERROR_NONE; +} + +API int capmgr_file_set_finish_cb(capmgr_file_h file, + capmgr_file_finish_cb cb, void *user_data) { + if (!file) + return CAPMGR_ERROR_INVALID_PARAMETER; + + file->finish_cb.callback = cb; + file->finish_cb.user_data = user_data; + + return CAPMGR_ERROR_NONE; +} + +API int capmgr_file_set_progress_cb(capmgr_file_h file, + capmgr_file_progress_cb cb, void *user_data) { + if (!file) + return CAPMGR_ERROR_INVALID_PARAMETER; + + file->progress_cb.callback = cb; + file->progress_cb.user_data = user_data; + + return CAPMGR_ERROR_NONE; +} + +void capmgr_send_file_callback(GVariant* result, void* user_data) { + capmgr_file_h file = reinterpret_cast(user_data); + LOG(INFO) << "Send File Callback called: " << file->path; + delete file->ds; + file->ds = nullptr; + + int r = 0; + g_variant_get(result, "(i)", &r); + LOG(DEBUG) << "result:" << r; + if (file->finish_cb.callback) + file->finish_cb.callback(file, r, file->finish_cb.user_data); +} + +void capmgr_progress_callback(GVariant* param, void* user_data) { + capmgr_file_h file = reinterpret_cast(user_data); + + gchar* file_path; + int64_t sent_size; + int64_t total_size; + + g_variant_get(param, "(sxx)", &file_path, &sent_size, &total_size); + // file_path may key for search handlers for multiple file handling. + + if (file->progress_cb.callback) { + file->progress_cb.callback(file, sent_size, total_size, + file->progress_cb.user_data); + } +} + +API int capmgr_file_send(capmgr_file_h file) { + if (!file || !file->device || !file->path) + return CAPMGR_ERROR_INVALID_PARAMETER; + + int ret; + char* device_id; + ret = capmgr_device_get_device_id(file->device, &device_id); + if (ret != CAPMGR_ERROR_NONE) { + LOG(ERROR) << "Failed to get device id"; + return CAPMGR_ERROR_INVALID_PARAMETER; + } + + GVariant* gv = g_variant_new("(&s&s)", device_id, file->path); + if (!gv) { + LOG(ERROR) << "Failed to create GVariant"; + free(device_id); + return CAPMGR_ERROR_INVALID_PARAMETER; + } + + file->ds = new capmgr::DBusSignal("SendFileProgressChanged"); + file->ds->RegisterHandler(capmgr_progress_callback, file); + file->ds->Subscribe(); + + if (!capmgr::ProxyCallAsync("SendFile", gv, capmgr_send_file_callback, + file)) { + LOG(ERROR) << "Failed to dbus method call"; + g_variant_unref(gv); + delete file->ds; + file->ds = nullptr; + free(device_id); + // errcode? + return CAPMGR_ERROR_INVALID_PARAMETER; + } + + g_variant_unref(gv); + free(device_id); + + return CAPMGR_ERROR_NONE; +} diff --git a/src/dbus.cc b/src/dbus.cc old mode 100644 new mode 100755 index edd3138..8b3c3f1 --- a/src/dbus.cc +++ b/src/dbus.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/dbus.h" +#include "src/dbus_signal.h" #include #include @@ -37,25 +38,93 @@ void MethodCallback(GObject* source_object, GAsyncResult* res, delete cbdata; } -} // namespace +void SignalCallback(GDBusProxy* proxy, gchar* sender_name, gchar* signal_name, + GVariant* parameters, gpointer user_data) { + capmgr::DBusSignal* ds = reinterpret_cast(user_data); -namespace capmgr { + LOG(INFO) << "Signal recieved " << signal_name; + if (g_strcmp0(ds->GetSignalName(), signal_name) == 0) { + LOG(INFO) << "progress callback called"; + ds->Emit(parameters); + } +} -bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb, - void* user_data) { +bool InitDBusProxy(GDBusConnection** connection, GDBusProxy** proxy) { GError* error = nullptr; GDBusConnection* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error); - if (!conn || error) { + if (!conn) { LOG(ERROR) << "g_bus_get_sync() failed: " << error->message; + g_object_unref(error); return false; } - GDBusProxy* proxy = g_dbus_proxy_new_sync(conn, + + GDBusProxy* p = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, nullptr, kDBusServiceName, kDBusObjectPath, kDBusInterfaceName, nullptr, &error); - if (!proxy || error) { + if (!p) { LOG(ERROR) << "g_dbus_proxy_new_sync() failed: " << error->message; + g_object_unref(error); + g_object_unref(conn); + return false; + } + + *connection = conn; + *proxy = p; + return true; +} + +void DisposeDBusProxy(GDBusConnection* conn, GDBusProxy* proxy) { + if (proxy) + g_object_unref(proxy); + if (conn) { + g_dbus_connection_flush_sync(conn, nullptr, nullptr); g_object_unref(conn); + } +} + +} // namespace + +namespace capmgr { + +DBusSignal::DBusSignal(const std::string& signal_name) + : signal_name_ { signal_name } {} + +DBusSignal::~DBusSignal() { + DisposeDBusProxy(this->conn_, this->proxy_); +} + +void DBusSignal::RegisterHandler(DBusCallback cb, void* user_data) { + this->cb_ = cb; + this->user_data_ = user_data; +} + +void DBusSignal::Emit(GVariant* param) { + this->cb_(param, this->user_data_); +} + +bool DBusSignal::Subscribe() { + if (!InitDBusProxy(&this->conn_, &this->proxy_)) { + LOG(ERROR) << "DBus initilization failed"; + return false; + } + + g_signal_connect(this->proxy_, "g-signal", G_CALLBACK(SignalCallback), this); + + return true; +} + +const char* DBusSignal::GetSignalName() { + return this->signal_name_.c_str(); +} + +bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb, + void* user_data) { + GDBusConnection* conn = nullptr; + GDBusProxy* proxy = nullptr; + + if (!InitDBusProxy(&conn, &proxy)) { + LOG(ERROR) << "DBus initilization failed"; return false; } @@ -67,9 +136,7 @@ bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb, g_dbus_proxy_call(proxy, method, params, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, MethodCallback, cbdata); - g_object_unref(proxy); - g_dbus_connection_flush_sync(conn, nullptr, nullptr); - g_object_unref(conn); + DisposeDBusProxy(conn, proxy); return true; } diff --git a/src/dbus.h b/src/dbus.h old mode 100644 new mode 100755 index 5520488..83336a3 --- a/src/dbus.h +++ b/src/dbus.h @@ -6,6 +6,9 @@ #define DBUS_H_ #include +#include + +#include #include "include/capability-manager.h" diff --git a/src/dbus_signal.h b/src/dbus_signal.h new file mode 100755 index 0000000..ea78cbf --- /dev/null +++ b/src/dbus_signal.h @@ -0,0 +1,36 @@ +// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef DBUS_SIGNAL_H_ +#define DBUS_SIGNAL_H_ + +#include +#include + +#include + +#include "src/dbus.h" + +namespace capmgr { + +class DBusSignal { + public: + explicit DBusSignal(const std::string& signal_name); + ~DBusSignal(); + void RegisterHandler(DBusCallback cb, void* user_data); + bool Subscribe(); + const char* GetSignalName(); + void Emit(GVariant* param); + + private: + std::string signal_name_; + DBusCallback cb_; + void* user_data_; + GDBusProxy* proxy_; + GDBusConnection* conn_; +}; + +} // namespace capmgr + +#endif // DBUS_SIGNAL_H_ diff --git a/tools/capmgr_test.cc b/tools/capmgr_test.cc old mode 100644 new mode 100755 index 76dcb79..d57b732 --- a/tools/capmgr_test.cc +++ b/tools/capmgr_test.cc @@ -10,6 +10,7 @@ #include #include "include/capability-manager.h" +#include "include/capability-manager_internal.h" namespace bpo = boost::program_options; @@ -43,6 +44,10 @@ class Client { const capmgr_app_control_h reply, capmgr_app_control_result_e result, void* user_data); + static int FileFinishCb(capmgr_file_h file, int result, void* user_data); + static int FileProgressCb(capmgr_file_h file, + int64_t sent_size, int64_t total_size, void* user_data); + GMainLoop* loop_; GDBusConnection* conn_; GDBusProxy* proxy_; @@ -213,24 +218,71 @@ void Client::SendFile(const std::string& device_id, return; } - if (file_path.empty()) { - std::cout << "File path is missing!" << std::endl; + capmgr_device_h device = nullptr; + struct cbdata cbdata = {&device, device_id}; + int ret = capmgr_device_foreach_devices(DeviceForeachCb, &cbdata); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_device_foreach_devices() failed: " << ret + << std::endl; + return; + } + + if (*cbdata.device == nullptr) { + std::cout << "There is no such device!" << std::endl; + return; + } + + capmgr_file_h file; + ret = capmgr_file_create(&file); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_file_create() failed: " << ret << std::endl; + capmgr_device_destroy(device); + return; + } + + ret = capmgr_file_set_device(file, device); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_file_set_device() failed: " << ret + << std::endl; + capmgr_device_destroy(device); + capmgr_file_destroy(file); + return; + } + + ret = capmgr_file_set_path(file, file_path.c_str()); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_file_set_path() failed: " << ret + << std::endl; + capmgr_device_destroy(device); + capmgr_file_destroy(file); return; } - std::cout << "Send file " << file_path << " to " << device_id << std::endl; + ret = capmgr_file_set_finish_cb(file, FileFinishCb, this); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_file_set_finish_cb() failed: " << ret + << std::endl; + capmgr_device_destroy(device); + capmgr_file_destroy(file); + return; + } - GVariant* params = g_variant_new("(ss)", device_id.c_str(), - file_path.c_str()); - if (!params) { - std::cout << "out of memory" << std::endl; + ret = capmgr_file_set_progress_cb(file, FileProgressCb, this); + if (ret != CAPMGR_ERROR_NONE) { + std::cout << "capmgr_file_set_progress_cb() failed: " << ret + << std::endl; + capmgr_device_destroy(device); + capmgr_file_destroy(file); return; } - GVariant* ret = ProxyCallSync("SendFile", params); + ret = capmgr_file_send(file); + if (ret != CAPMGR_ERROR_NONE) + std::cout << "capmgr_file_send failed: " << ret + << std::endl; - g_object_unref(params); - g_object_unref(ret); + capmgr_device_destroy(device); + WaitForResult(); } GVariant* Client::ProxyCallSync(const char* method, GVariant* params) { @@ -252,6 +304,25 @@ void Client::Quit() { g_main_loop_quit(loop_); } +int Client::FileFinishCb(capmgr_file_h file, + int result, void* user_data) { + std::cout << "FileFinishCb called: " << result << std::endl; + + capmgr_file_destroy(file); + + Client* client = static_cast(user_data); + client->Quit(); + return 0; +} + +int Client::FileProgressCb(capmgr_file_h file, int64_t sent_size, + int64_t total_size, void* user_data) { + std::cout << "FileProgressCb called (" + << sent_size << "/" << total_size << ")bytes sent" << std::endl; + + return 0; +} + int Client::AppControlCb(const capmgr_app_control_h request, const capmgr_app_control_h reply, capmgr_app_control_result_e result, void* user_data) { -- 2.7.4