USD: Add dbus thread
authorJan Cybulski <j.cybulski@samsung.com>
Tue, 14 Jul 2015 09:38:19 +0000 (11:38 +0200)
committerStanislaw Wadas <s.wadas@samsung.com>
Wed, 2 Dec 2015 12:50:46 +0000 (13:50 +0100)
Add class for maintaining thread needed for dbus main loop.
Dbus communication is needed because popup mechanism used this IPC.

Change-Id: Ifd5c34dac3144906d156ad14e151f0684bfa790f
Signed-off-by: Jan Cybulski <j.cybulski@samsung.com>
Signed-off-by: Stanislaw Wadas <s.wadas@samsung.com>
USD/src/CMakeLists.txt
USD/src/client/client-common.cpp
USD/src/common/usb-access-map.cpp
USD/src/common/usb-access-map.h
USD/src/main/dbus-manager.cpp [new file with mode: 0644]
USD/src/main/dbus-manager.h [new file with mode: 0644]
USD/src/main/server2-main.cpp
USD/src/main/socket-manager.cpp
packaging/capi-system-usbhost.spec

index ecad22b824a41abc11b0f15cfca75e5c2ac8a0ce..223adfc2b901931a0b59c0e4bff7b0bc658f9d7b 100644 (file)
@@ -2,6 +2,7 @@ PKG_CHECK_MODULES(USD_DEP
     dlog
     libsmack
     libsystemd-daemon
+    dbus-1
     REQUIRED
     )
 
@@ -14,6 +15,9 @@ SET(USD_SOURCES
     ${SERVER2_PATH}/main/socket-manager.cpp
     ${SERVER2_PATH}/main/server2-main.cpp
     ${SERVER2_PATH}/service/usb-access.cpp
+    ${SERVER2_PATH}/main/dbus-manager.cpp
+    ${SERVER2_PATH}/client/usb-access-client.cpp
+    ${SERVER2_PATH}/client/client-common.cpp
     )
 
 SET_SOURCE_FILES_PROPERTIES(
index 8d57fd8e2c92892ed2e9f7cd64aa4a8e489a2e90..b0ce9c6ea54e0448daaa80e7f6a3e19dd19d035e 100644 (file)
@@ -37,9 +37,9 @@
 #include <message-buffer.h>
 
 #include <usb-security-daemon.h>
-
+/*
 IMPLEMENT_SAFE_SINGLETON(USD::Log::LogSystem);
-
+*/
 namespace {
 
 const int POLL_TIMEOUT = 2000;
index 97a5922d44ad36ae6ccb89ca8c107e1e1f999e4e..ae951629dc83e2e0e41ef84b8e3cc4329cee8ff2 100644 (file)
@@ -148,6 +148,12 @@ const std::string &USBDevicePath::getSysFSPath() const
     return m_sysPath;
 }
 
+const std::string &USBDevicePath::getTopology() const
+{
+    //todo get topology!
+    return m_sysPath;
+}
+
 dev_t USBDevicePath::getDev() const
 {
     return m_dev;
index 5f7be9c4c72fc5b41c6240c08d8d3ed34afc6c6b..65d06a4458b32ce74c7e2077d33680a2507ee199 100644 (file)
@@ -46,6 +46,7 @@ public:
     /* Never call this constructor with SysFS path received from user! */
     USBDevicePath(const std::string &path, PathType path_type);
     const std::string &getSysFSPath() const;
+    const std::string &getTopology() const;
     dev_t getDev() const;
 
     friend std::ostream &operator<<(std::ostream &stream,
@@ -75,6 +76,7 @@ public:
 
     friend std::ostream &operator<<(std::ostream &stream,
                                     const USBDeviceId &id);
+    const char *getTopology() {return m_path.getTopology().c_str();}
 
 private:
     void initDevId(const std::string &sys_path);
@@ -117,6 +119,7 @@ public:
 
     friend std::ostream& operator<<(std::ostream& stream,
                                     const PolicySubjectId& id);
+    const char *getAppData() {return m_smk.c_str();}
 
 private:
     std::string m_smk;
@@ -136,6 +139,8 @@ public:
     bool operator==(const USBAccessMapKey &r) const;
     friend std::ostream& operator<<(std::ostream& stream,
                                     const USBAccessMapKey& key);
+    const char* getDeviceTopology() {return m_device.getTopology();}
+    const char* getAppData() {return m_subject.getAppData();}
 
 private:
     PolicySubjectId m_subject;
diff --git a/USD/src/main/dbus-manager.cpp b/USD/src/main/dbus-manager.cpp
new file mode 100644 (file)
index 0000000..8c2a852
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        dbus-manager.cpp
+ * @author      Jan Cybulski <j.cybulski@samsung.com>
+ * @version     1.0
+ * @brief       Implementation of dbus communication threads.
+ */
+
+
+#include "dbus-manager.h"
+#include <dbus/dbus.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+
+#include <thread>
+#include <string>
+#include <dpl/log/log.h>
+
+
+namespace USD {
+
+#define USD_USB_DEVICE_CONFIRM_SIGNAL   "USBDeviceOpenResult"
+#define USD_INTERFACE                   "org.tizen.system.usd"
+#define USD_PATH                        "/Org/Tizen/System/USD"
+
+#define DEST_NAME     "org.tizen.system.popup"
+#define DEST_IFACE    "org.tizen.system.popup.System"
+#define DEST_PATH     "/Org/Tizen/System/Popup/System"
+#define DEST_METHOD   "PopupLaunch"
+
+const std::string CONTENT = "_SYSPOPUP_CONTENT_";
+const std::string POPUP_NAME = "usb_device_confirm";
+
+
+//#define BUS_TYPE          (DBUS_BUS_SESSION)
+#define BUS_TYPE          (DBUS_BUS_SYSTEM)
+
+
+enum button_selected_e {
+    USB_DEVICE_CONFIRM_OK,
+    USB_DEVICE_CONFIRM_NOK,
+  };
+
+int done;
+int get_sender_pid(DBusConnection *conn, const char *sender);
+
+static DBusHandlerResult filter_func(DBusConnection *conn,
+        DBusMessage *msg,
+        void *data)
+{
+    DBusError err;
+    dbus_bool_t handled = FALSE;
+    int result = 0;
+    DbusManager *pDM = (DbusManager *)data;
+
+    LogError("filter_func");
+
+    if (dbus_message_is_signal(msg, USD_INTERFACE, USD_USB_DEVICE_CONFIRM_SIGNAL))
+    {
+        dbus_error_init(&err);
+        dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
+        if (dbus_error_is_set(&err))
+        {
+            LogError("dbus_message_get_args failed: " << err.message);
+            dbus_error_free(&err);
+            handled = TRUE;
+            //handle error?
+        }
+        else
+        {
+
+            int recv_pid = get_sender_pid(conn, dbus_message_get_sender(msg));
+            handled = pDM->handlePopup(recv_pid, result);
+            LogDebug("Popup sender pid:" << recv_pid);
+
+        }
+    }
+
+    return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+}
+
+int add_dict_entries(DBusMessage *msg, const char *str1, const char *str2)
+{
+    DBusMessageIter args, array_iter, dict_iter;
+    dbus_message_iter_init_append(msg, &args);
+
+    if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+            DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+            DBUS_TYPE_STRING_AS_STRING
+            DBUS_TYPE_STRING_AS_STRING
+            DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+            &array_iter))
+        return 0;
+
+    if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter))
+        return 0;
+
+    if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &str1))
+        return 0;
+
+    if (!dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &str2))
+        return 0;
+
+    if (!dbus_message_iter_close_container(&array_iter, &dict_iter))
+        return 0;
+
+    if (!dbus_message_iter_close_container(&args, &array_iter))
+        return 0;
+    return 1;
+}
+
+int get_sender_pid(DBusConnection *conn, const char *sender)
+{
+    int pid = 0;
+    DBusMessage *msg = NULL, *reply = NULL;
+    DBusError err;
+
+    if (!conn || !sender)
+        goto cleanup;
+
+    msg = dbus_message_new_method_call("org.freedesktop.DBus",
+            "/org/freedesktop/DBus",
+            "org.freedesktop.DBus",
+            "GetConnectionUnixProcessID");
+    if (msg == NULL)
+        goto cleanup;
+
+    dbus_message_append_args(msg, DBUS_TYPE_STRING, &sender, DBUS_TYPE_INVALID);
+
+    dbus_error_init(&err);
+    reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000, &err);
+    if (dbus_error_is_set(&err))
+    {
+        LogError("dbus_connection_send_with_reply_and_block: " << err.message);
+        dbus_error_free(&err);
+        goto cleanup;
+    }
+
+    dbus_message_get_args(reply, &err, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID);
+    if (dbus_error_is_set(&err))
+    {
+        LogError("dbus_message_get_args: " << err.message);
+        dbus_error_free(&err);
+        goto cleanup;
+    }
+
+    cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    return pid;
+}
+
+int request_popup(DBusConnection *conn, PopupData dp)
+{
+    int pid = 0;
+    DBusMessage *msg = NULL, *reply = NULL;
+    DBusError err;
+    (void) dp;/* This should be used to present user with proper data.
+    As for now popup mechanism does not provide functionality allowing to pass
+    additional data to popup to be displayed. Popup prints fixed text.
+    We may and should change it later and construct some text out of "dp"
+    and pass it to popup mechanism.*/
+
+    if (!conn)
+    {
+        LogError("Connection was not setup before");
+        goto cleanup;
+    }
+
+    msg = dbus_message_new_method_call(DEST_NAME, DEST_PATH, DEST_IFACE, DEST_METHOD);
+    if (!msg)
+    {
+        LogError("Method call was not created");
+        goto cleanup;
+    }
+
+    if (!add_dict_entries(msg, CONTENT.c_str(), POPUP_NAME.c_str()))
+    {
+        LogError("add_dict_entries failed");
+        goto cleanup;
+    }
+
+    dbus_error_init(&err);
+    reply = dbus_connection_send_with_reply_and_block(conn, msg, 1000/*one second*/, &err);
+    if (dbus_error_is_set(&err))
+    {
+        LogError("dbus_connection_send_with_reply_and_block failed " << err.message);
+        dbus_error_free(&err);
+        goto cleanup;
+    }
+
+    dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID);
+    if (dbus_error_is_set(&err))
+    {
+        LogError("dbus_message_get_args failed: " << err.message);
+        dbus_error_free(&err);
+        goto cleanup;
+    }
+
+    cleanup:
+    if (msg)
+        dbus_message_unref(msg);
+    if (reply)
+        dbus_message_unref(reply);
+    LogError("Got answer with pid:" << pid);
+    return pid;
+}
+
+DbusManager::DbusManager(): m_state(State::NoThread), m_quit(false){;}
+
+void DbusManager::Create() {
+    LogDebug("Creating dbus thread");
+    assert(m_state == State::NoThread);
+    m_conn = setupDbusConnection();
+    if (!m_conn) {
+        LogError("Could not setup Dbus Connection");
+        throw -1; //TODO
+    }
+    m_thread = std::thread(ThreadLoopStatic, this);
+    m_state = State::Work;
+}
+
+void DbusManager::notifyPopupHandled(pid_t pid) {
+    LogDebug("Got popup answer notify");
+    m_popupHandleMutex.lock();
+    this->m_popupMap.erase(pid);
+    m_popupHandleMutex.unlock();
+}
+
+bool DbusManager::waitForPopupHandled(pid_t popup_pid) {
+    int delay = 50;
+    while (delay > 0) {
+        delay--;
+        LogDebug("Waiting for popup, popup pid: " << popup_pid);
+        {
+            std::lock_guard<std::mutex> lock(m_popupHandleMutex);
+            if(this->m_popupMap.find(popup_pid) == m_popupMap.end()) {
+                return true;
+            }
+        }
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+    return false;
+}
+
+
+bool DbusManager::handlePopup(pid_t pid, int popupResult) {
+    std::lock_guard<std::mutex> lock(m_popupHandleMutex);
+
+    //PopupData *popupData;
+    auto it = m_popupMap.find(pid);
+    if (it != m_popupMap.end()) {
+        //popupData = &*it;
+        const char *device = getPopupDevice(pid);
+        const char *application = getPopupApp(pid);
+        bool allow = (popupResult == USB_DEVICE_CONFIRM_OK);
+        LogDebug("Got popup answer notify from pid" << pid);
+        this->m_popupMap.erase(pid);
+        usd_setup_usb_device_access(device, application, allow);
+        return true;
+    }
+    LogWarning("Someone tries to fake popup answer data... ");
+    return false;
+
+}
+
+void DbusManager::Join() {
+    LogDebug("Joining dbus thread");
+    assert(m_state != State::NoThread);
+    {
+        std::lock_guard<std::mutex> lock(m_popupHandleMutex);
+        m_quit = true;
+        m_state = State::NoThread;
+
+    }
+    m_thread.join();
+    LogDebug("Joined dbus thread");
+
+}
+
+DBusConnection* DbusManager::setupDbusConnection()
+{
+    DBusError err;
+    DBusConnection *conn;
+
+
+    dbus_error_init(&err);
+    conn = dbus_bus_get(BUS_TYPE, &err);
+    if (dbus_error_is_set(&err))
+    {
+        LogError("Could not get bus" << err.message);
+        dbus_error_free(&err);
+
+        return NULL;
+    }
+    assert(conn != NULL);
+    LogDebug("Bus obtained");
+
+    dbus_bus_add_match(conn,
+            "type='signal',interface='" USD_INTERFACE "'",
+            &err);
+    if (dbus_error_is_set(&err))
+    {
+        dbus_error_free(&err);
+        LogError("Could not add match");
+        return NULL;
+    }
+    LogDebug("Match added");
+
+    if (!dbus_connection_add_filter(conn, filter_func, this, NULL))
+    {
+        LogError("Could not add filter");
+        return NULL;
+    }
+    LogDebug("Filter added");
+    return conn;
+}
+
+
+pid_t DbusManager::addPopupRequest(const PopupData &popupData)
+{
+    LogDebug("Pushing popup request " << popupData);
+    std::lock_guard<std::mutex> lock(m_eventQueueMutex);
+    pid_t newPopupPid = request_popup(this->m_conn, popupData);
+    m_popupMap.insert(std::pair<pid_t, PopupData>(newPopupPid, popupData));
+    return newPopupPid;
+
+}
+
+const char *DbusManager::getPopupDevice(pid_t pid) {
+    return m_popupMap.at(pid).getDeviceTopology();
+}
+const char *DbusManager::getPopupApp(pid_t pid) {
+    return m_popupMap.at(pid).getAppData();
+}
+
+void DbusManager::ThreadLoop() {
+    for (;;) {
+
+        {
+            std::lock_guard<std::mutex> lock(m_eventQueueMutex);
+            if (m_quit) {
+                LogDebug("Quitting dbus loop");
+                return;
+            }
+        }
+        dbus_connection_read_write_dispatch(m_conn, 100);
+
+    }
+}
+
+
+}/*namespace usd*/
diff --git a/USD/src/main/dbus-manager.h b/USD/src/main/dbus-manager.h
new file mode 100644 (file)
index 0000000..f69c746
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        dbus-manager.h
+ * @author      Jan Cybulski <j.cybulski@samsung.com>
+ * @version     1.0
+ * @brief       Header for dbus communication threads classes.
+ */
+
+#ifndef _DBUS_MANAGER_H_
+#define _DBUS_MANAGER_H_
+
+
+#include <service-thread.h>
+#include <generic-socket-manager.h>
+#include <dbus/dbus.h>
+#include <usb-access-map.h>
+#include <usb-security-daemon.h>
+#include <set>
+
+namespace USD {
+
+typedef USBAccessMapKey PopupData;
+
+
+class DbusManager{
+public:
+    pid_t addPopupRequest(const PopupData &popupData);
+    const char *getPopupDevice(pid_t pid);
+    const char *getPopupApp(pid_t pid);
+
+    enum class State {
+        NoThread,
+        Work,
+        Wait,
+    };
+
+    DbusManager();
+    void Create();
+    void Join();
+    virtual ~DbusManager()
+    {
+        if (m_state != State::NoThread)
+            Join();
+    }
+
+    void notifyPopupHandled(pid_t pid);
+    bool waitForPopupHandled(pid_t pid);
+    bool isPidActivePopup(pid_t pid);
+    bool handlePopup(pid_t pid, int popupResult);
+
+    protected:
+        std::mutex m_popupHandleMutex;
+        DBusConnection *m_conn;
+        std::thread m_thread;
+        std::mutex m_eventQueueMutex;
+
+
+      //  std::condition_variable m_waitCondition;
+        std::map<pid_t, PopupData> m_popupMap;
+        std::queue<PopupData> m_popupQueue;
+        State m_state;
+        bool m_quit;
+
+        DBusConnection* setupDbusConnection();
+        static void ThreadLoopStatic(DbusManager *ptr) { ptr->ThreadLoop(); }
+        void ThreadLoop();
+};
+
+}
+
+
+#endif /*_DBUS_MANAGER_H_*/
index 3429abbda39e3145fd486bc33f69cc4f167a1f2f..0431c3ff45e0702eb78acab4f25c8eadd9f89e63 100644 (file)
@@ -29,6 +29,8 @@
 #include <dpl/singleton_safe_impl.h>
 
 #include <socket-manager.h>
+#include <dbus-manager.h>
+
 
 #include <usb-access.h>
 
@@ -60,6 +62,9 @@ void registerSocketService(USD::SocketManager &manager, const std::string& servi
         delete service;
 }
 
+
+USD::DbusManager dbusmanager;
+
 int main(void) {
 
     UNHANDLED_EXCEPTION_HANDLER_BEGIN
@@ -78,9 +83,13 @@ int main(void) {
         LogInfo("Start!");
         USD::SocketManager manager;
 
-        REGISTER_SOCKET_SERVICE(manager, USD::USBAccessService);
 
+        REGISTER_SOCKET_SERVICE(manager, USD::USBAccessService);
+        dbusmanager.Create();
         manager.MainLoop();
+        dbusmanager.Join();
+        LogDebug("Quit");
+
     }
     UNHANDLED_EXCEPTION_HANDLER_END
     return 0;
index 935635c2a0a78bec5cc73dcb7a035854b15b3961..fa073b40bfac6c62d8705c76dc6b4f65a312a739 100644 (file)
@@ -391,6 +391,10 @@ void SocketManager::MainLoop() {
         int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout);
 
         if (0 == ret) { // timeout
+            if (m_timeoutQueue.empty()) {
+                LogError("would abort");
+                continue;
+            }
             Assert(!m_timeoutQueue.empty());
 
             Timeout pqTimeout = m_timeoutQueue.top();
index 1e08622e2f7e7be015c9a7b8a9b6d47d5bb1113d..870aeaeb750572e012c988694e48ab4877bc3f21 100644 (file)
@@ -20,6 +20,7 @@ BuildRequires: libcap-devel
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(libsystemd-daemon)
 BuildRequires: pkgconfig(libsystemd-journal)
+BuildRequires: pkgconfig(dbus-1)
 %{?systemd_requires}
 
 %description