--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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_*/