Make notification backend sane again 71/99671/6
authorZofia Abramowska <z.abramowska@samsung.com>
Wed, 16 Nov 2016 14:54:15 +0000 (15:54 +0100)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Wed, 30 Nov 2016 13:42:16 +0000 (14:42 +0100)
Because notification backend used to be socket service
and backends were created per cynara request, many ugly
tricks had to be implemented. Now, thanks to notification
daemon being socket service, notification backend is back
to being proper socket client.

Change-Id: Iee61b79f16346844a2bc0d43c131bde0611ddfa6

13 files changed:
src/agent/CMakeLists.txt
src/agent/main/NotificationTalker.cpp [deleted file]
src/agent/main/NotificationTalker.h [deleted file]
src/agent/ui/FdNotifyObject.cpp [new file with mode: 0644]
src/agent/ui/FdNotifyObject.h [moved from src/common/types/Protocol.h with 56% similarity]
src/agent/ui/NotificationBackend.cpp
src/agent/ui/NotificationBackend.h
src/common/config/Path.cpp
src/common/config/Path.h
src/common/socket/Poll.h
test/CMakeLists.txt
test/daemon/.notificationTalker.cpp.swp [deleted file]
test/daemon/notificationTalker.cpp [deleted file]

index 507b2f5..bb530f0 100644 (file)
@@ -32,8 +32,8 @@ SET(ASKUSER_SOURCES
     ${ASKUSER_AGENT_PATH}/main/Agent.cpp
     ${ASKUSER_AGENT_PATH}/main/CynaraTalker.cpp
     ${ASKUSER_AGENT_PATH}/main/main.cpp
-    ${ASKUSER_AGENT_PATH}/main/NotificationTalker.cpp
     ${ASKUSER_AGENT_PATH}/ui/NotificationBackend.cpp
+    ${ASKUSER_AGENT_PATH}/ui/FdNotifyObject.cpp
     )
 
 INCLUDE_DIRECTORIES(
diff --git a/src/agent/main/NotificationTalker.cpp b/src/agent/main/NotificationTalker.cpp
deleted file mode 100644 (file)
index ce7d640..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- *  Copyright (c) 2016 Samsung Electronics Co.
- *
- *  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        src/daemon/NotificationTalker.cpp
- * @author      Oskar Świtalski <o.switalski@samsung.com>
- * @brief       Definition of NotificationTalker class
- */
-
-#include "NotificationTalker.h"
-
-#include <algorithm>
-#include <cstring>
-#include <cynara-creds-socket.h>
-
-#include <exception/ErrnoException.h>
-#include <exception/CynaraException.h>
-#include <log/alog.h>
-#include <socket/Poll.h>
-#include <socket/Socket.h>
-#include <translator/Translator.h>
-#include <config/Path.h>
-#include <types/Protocol.h>
-
-namespace {
-
-std::string getUserFromSocket(const AskUser::Socket &sock) {
-    char *user = nullptr;
-
-    int ret = cynara_creds_socket_get_user(sock.getFd(), USER_METHOD_DEFAULT,&user);
-    if (ret != CYNARA_API_SUCCESS) {
-        throw AskUser::CynaraException("cynara_creds_socket_get_user", ret);
-    }
-
-    std::unique_ptr<char, decltype(free) *> userPtr(user, ::free);
-    return user;
-}
-
-}
-
-namespace AskUser {
-
-namespace Agent {
-
-NotificationTalker::NotificationTalker()
-    : m_poll(10),
-      m_serverSocket(Socket::PeerType::SERVER),
-      m_failed(true),
-      m_stopflag(false)
-{
-    try {
-        m_serverSocket.bindAndListen(Path::getSocketPath());
-        m_thread = std::thread(&NotificationTalker::run, this);
-        m_failed = false;
-    } catch (const Exception &e) {
-        setErrorMsg(e.what());
-    } catch (const std::exception &e) {
-        setErrorMsg(std::string("caught std::exception: ") + e.what());
-    } catch (...) {
-        setErrorMsg("caught unknown exception");
-    }
-}
-
-void NotificationTalker::setErrorMsg(std::string s)
-{
-    m_errorMsg = std::move(s);
-}
-
-void NotificationTalker::parseRequest(RequestType type, NotificationRequest request)
-{
-    std::lock_guard<std::mutex> lock(m_bfLock);
-
-    if (!m_responseHandler) {
-        ALOGE("Response handler not set!");
-        return;
-    }
-
-    switch (type) {
-    case RequestType::RT_Close:
-        ALOGD("Close service");
-        stop();
-        return;
-    case RequestType::RT_Action:
-        ALOGD("Add request: " << request.id);
-        addRequest(std::move(request));
-        return;
-    case RequestType::RT_Cancel:
-        ALOGD("Cancel request: " << request.id);
-        removeRequest(request.id);
-        return;
-    default:
-        return;
-    }
-}
-
-void NotificationTalker::addRequest(NotificationRequest &&request)
-{
-    auto &queue = m_requests[request.data.user];
-    auto it = std::find_if(queue.begin(), queue.end(),
-            [&request](const NotificationRequest &req){return req.id == request.id;}
-        );
-
-    if (it == queue.end()) {
-        queue.emplace_back(std::move(request));
-    } else {
-        ALOGD("Cynara request already exists");
-    }
-}
-
-void NotificationTalker::removeRequest(RequestId id)
-{
-    for (auto &pair : m_requests) {
-        auto &queue = std::get<1>(pair);
-        auto it = std::find_if(queue.begin(), queue.end(),
-                [&id](const NotificationRequest &req){return req.id == id;}
-            );
-        if (it == queue.end()) {
-            ALOGW("Removing non-existent request");
-            return;
-        }
-        if (it == queue.begin()) {
-            auto user = std::get<0>(pair);
-            auto it2 = m_userToPeer.find(user);
-            if (it2 != m_userToPeer.end())
-                sendDismiss(std::get<1>(*it2));
-        }
-
-        queue.erase(it);
-    }
-}
-
-void NotificationTalker::stop()
-{
-    m_stopflag = true;
-}
-
-void NotificationTalker::clear()
-{
-    m_fdStatus.clear();
-    m_fdToUser.clear();
-    m_userToPeer.clear();
-
-    m_serverSocket.close();
-}
-
-NotificationTalker::~NotificationTalker()
-{
-    stop();
-    clear();
-    m_thread.join();
-}
-
-void NotificationTalker::sendRequest(Socket &peerSocket, const NotificationRequest &request)
-{
-    int fd = peerSocket.getFd();
-    m_fdStatus[fd] = false;
-
-    std::string data = Translator::Gui::notificationRequestToData(request.id,
-                                                                  request.data.client,
-                                                                  request.data.privilege);
-    if (!peerSocket.send(data)) {
-        remove(fd);
-        return;
-    }
-}
-
-void NotificationTalker::sendDismiss(Socket &peerSocket)
-{
-    int fd = peerSocket.getFd();
-    if (!m_fdStatus[fd]) {
-        if (peerSocket.send(Protocol::dissmisCode)) {
-            remove(fd);
-            return;
-        }
-        m_fdStatus[fd] = true;
-    }
-}
-
-void NotificationTalker::parseResponse(NotificationResponse response, Socket &peerSocket)
-{
-    int fd = peerSocket.getFd();
-    auto &queue = m_requests[m_fdToUser[fd]];
-    if (queue.empty()) {
-        ALOGD("Request canceled");
-        m_fdStatus[fd] = true;
-        return;
-    }
-
-    NotificationRequest request = queue.front();
-    if (request.id != response.id) {
-        ALOGD("Request canceled");
-        m_fdStatus[fd] = true;
-        return;
-    }
-
-    queue.pop_front();
-    ALOGD("For user: <" << request.data.user
-          << "> client: <" << request.data.client
-          << "> privilege: <" << request.data.privilege
-          << "> received: <" << Translator::Gui::responseToString(response.response) << ">");
-
-    m_responseHandler(response);
-
-    if (peerSocket.send(Protocol::ackCode)) {
-        remove(fd);
-        return;
-    }
-
-    m_fdStatus[fd] = true;
-}
-
-bool NotificationTalker::recvResponse(Socket &peerSocket, NotificationResponse &response)
-{
-    int requestId, responseType;
-    if (!peerSocket.recv(requestId) || !peerSocket.recv(responseType)) {
-        ALOGE("Failed to fetch response");
-        return false;
-    }
-    response.id = static_cast<RequestId>(requestId);
-    response.response = static_cast<NResponseType>(responseType);
-    return true;
-}
-
-void NotificationTalker::recvResponses(int &rv)
-{
-    std::vector<std::string> usersToDelete;
-    for (auto &userPeer : m_userToPeer) {
-        if (!rv) break;
-        auto &peerSocket = userPeer.second;
-        int fd = peerSocket.getFd();
-        if (m_poll.getEvents(fd) | POLLIN) {
-            --rv;
-
-            NotificationResponse response;
-            if (recvResponse(peerSocket, response)) {
-                parseResponse(response, peerSocket);
-            } else {
-                m_fdToUser.erase(fd);
-                m_fdStatus.erase(fd);
-                usersToDelete.push_back(userPeer.first);
-            }
-        }
-    }
-
-    for (auto &user : usersToDelete) {
-        m_userToPeer.erase(user);
-    }
-}
-
-void NotificationTalker::newConnection(int &rv)
-{
-    if (m_poll.getEvents(m_serverSocket.getFd()) | POLLIN) {
-        --rv;
-        Socket peerSocket = m_serverSocket.accept();
-        int peerFd = peerSocket.getFd();
-
-        try {
-            std::string user = getUserFromSocket(peerSocket);
-
-            auto it = m_userToPeer.find(user);
-            // Same user connected second time
-            if (it != m_userToPeer.end()) {
-                remove(it->second.getFd());
-            }
-
-            m_userToPeer.emplace(user, std::move(peerSocket));
-            m_fdToUser[peerFd] = user;
-            m_fdStatus[peerFd] = true;
-
-            ALOGD("Accepted new conection for user: " << user);
-        } catch (...) {
-            peerSocket.close();
-            throw;
-        }
-    }
-}
-
-void NotificationTalker::remove(int fd)
-{
-    auto user = m_fdToUser[fd];
-    m_fdToUser.erase(fd);
-    m_userToPeer.erase(user);
-    m_fdStatus.erase(fd);
-}
-
-void NotificationTalker::run()
-{
-    try {
-        ALOGD("Notification loop started");
-        while (!m_stopflag) {
-            std::lock_guard<std::mutex> lock(m_bfLock);
-
-            m_poll.setEvents(m_serverSocket.getFd(), POLLIN);
-
-            for (auto &userPeer : m_userToPeer)
-                m_poll.setEvents(userPeer.second.getFd(), POLLIN);
-
-            int rv = m_poll.wait(100);
-
-            if (m_stopflag) {
-                clear();
-                break;
-            }
-
-            if (rv) {
-                newConnection(rv);
-                recvResponses(rv);
-            }
-            for (auto &userPeer : m_userToPeer) {
-                const std::string &user = userPeer.first;
-                Socket &socketPeer = userPeer.second;
-
-                auto &queue = m_requests[user];
-                if (m_fdStatus.at(socketPeer.getFd()) && !queue.empty()) {
-                    sendRequest(socketPeer, queue.front());
-                }
-            }
-        }
-        ALOGD("NotificationTalker loop ended");
-    } catch (const std::exception &e) {
-        setErrorMsg(e.what());
-        m_failed = true;
-    } catch (...) {
-        setErrorMsg("unknown error");
-        m_failed = true;
-    }
-
-    if (m_failed && m_responseHandler) {
-        for (auto &userQueue : m_requests) {
-            auto &queue = userQueue.second;
-            for (auto &request : queue) {
-                m_responseHandler({request.id, NResponseType::Error});
-            }
-        }
-    }
-}
-
-} /* namespace Agent */
-
-} /* namespace AskUser */
diff --git a/src/agent/main/NotificationTalker.h b/src/agent/main/NotificationTalker.h
deleted file mode 100644 (file)
index ea3fdb9..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *  Copyright (c) 2016 Samsung Electronics Co.
- *
- *  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        src/daemon/NotificationTalker.cpp
- * @author      Oskar Świtalski <o.switalski@samsung.com>
- * @brief       Declaration of NotificationTalker class
- */
-
-#pragma once
-
-#include <cerrno>
-#include <deque>
-#include <functional>
-#include <map>
-#include <mutex>
-#include <string>
-#include <thread>
-
-#include <socket/Socket.h>
-#include <socket/Poll.h>
-#include <types/RequestId.h>
-#include <types/NotificationResponse.h>
-#include <types/NotificationRequest.h>
-
-#include <main/Request.h>
-
-namespace AskUser {
-
-namespace Agent {
-
-typedef std::pair<std::string, int> UserToFdPair;
-typedef std::map<std::string, Socket> UserToPeerMap;
-typedef std::map<int, std::string> FdToUserMap;
-typedef std::map<int, bool> FdStatus;
-
-typedef std::map<std::string, std::deque<NotificationRequest>> RequestsQueue;
-
-typedef std::function<void(NotificationResponse)> ResponseHandler;
-
-class NotificationTalker
-{
-public:
-    NotificationTalker();
-    bool isFailed() { return m_failed; }
-    std::string getErrorMsg() { return m_errorMsg; }
-    void setResponseHandler(ResponseHandler responseHandler)
-    {
-        m_responseHandler = responseHandler;
-    }
-    void parseRequest(RequestType type, NotificationRequest request);
-    virtual void stop();
-
-    virtual ~NotificationTalker();
-
-protected:
-    void setErrorMsg(std::string s);
-    void run();
-    void parseResponse(NotificationResponse response, Socket &peerSocket);
-    bool recvResponse(Socket &peerSocket, NotificationResponse &response);
-    void recvResponses(int &rv);
-
-    void newConnection(int &rv);
-    void remove(int fd);
-
-    void clear();
-
-    virtual void addRequest(NotificationRequest &&request);
-    virtual void removeRequest(RequestId id);
-    virtual void sendRequest(Socket &peerSocket, const NotificationRequest &request);
-    virtual void sendDismiss(Socket &peerSocket);
-
-    ResponseHandler m_responseHandler;
-
-    UserToPeerMap m_userToPeer;
-    FdToUserMap m_fdToUser;
-    FdStatus m_fdStatus;
-    Poll m_poll;
-    Socket m_serverSocket;
-    std::vector<Socket> m_peers;
-    bool m_failed;
-    std::string m_errorMsg;
-
-    RequestsQueue m_requests;
-    std::mutex m_bfLock;
-
-    std::thread m_thread;
-    bool m_stopflag;
-};
-
-} /* namespace Agent */
-
-} /* namespace AskUser */
diff --git a/src/agent/ui/FdNotifyObject.cpp b/src/agent/ui/FdNotifyObject.cpp
new file mode 100644 (file)
index 0000000..df0338d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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        src/monitor/notify/FdNotifyObject.cpp
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @version     1.0
+ * @brief       This file contains implementation of cynara's fd notification object
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <unistd.h>
+
+#include <log/alog.h>
+
+#include "FdNotifyObject.h"
+
+namespace AskUser {
+
+FdNotifyObject::FdNotifyObject() : m_pipeFd{-1, -1} {
+}
+
+bool FdNotifyObject::init(void) {
+    int ret = pipe(m_pipeFd);
+    if (ret != 0) {
+        int err = errno;
+        ALOGE("Couldn't initialize pipes: " << strerror(err));
+        return false;
+    }
+    return true;
+}
+
+int FdNotifyObject::getNotifyFd(void) {
+    return m_pipeFd[0];
+}
+
+bool FdNotifyObject::notify(void) {
+    const char wakeup[] = "w";
+    int ret = TEMP_FAILURE_RETRY(write(m_pipeFd[1], wakeup, sizeof(wakeup)));
+    if (ret == -1) {
+        return false;
+    }
+    return true;
+}
+
+FdNotifyObject::~FdNotifyObject() {
+    if (m_pipeFd[0] != -1)
+        close(m_pipeFd[0]);
+    if (m_pipeFd[1] != -1)
+        close(m_pipeFd[1]);
+}
+
+} /* namespace Cynara */
similarity index 56%
rename from src/common/types/Protocol.h
rename to src/agent/ui/FdNotifyObject.h
index c97a2ed..db7ceb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 Samsung Electronics Co.
+ *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  limitations under the License
  */
 /**
- * @file        src/common/types/Protocol.h
- * @author      Oskar Świtalski <o.switalski@samsung.com>
- * @brief       Definition of common types and consts
+ * @file        src/agent/ui/FdNotifyObject.h
+ * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @version     1.0
+ * @brief       This file contains definition of fd notification object
  */
 
 #pragma once
 
-#include <cstdint>
-
 namespace AskUser {
-namespace Protocol {
 
-constexpr int dissmisCode = 0xDE;
-constexpr int ackCode = 0xAC;
+class FdNotifyObject {
+public:
+    FdNotifyObject();
+    ~FdNotifyObject();
+    int getNotifyFd(void);
+    bool init(void);
+    bool notify(void);
+private:
+    int m_pipeFd[2];
+};
 
-} // namespace Protocol
-} // namespace AskUser
+} /* namespace AskUser */
index 09f01f2..16ac73b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  limitations under the License
  */
 /**
- * @file        NotificationBackend.cpp
+ * @file        src/daemon/NotificationBackend.cpp
  * @author      Zofia Abramowska <z.abramowska@samsung.com>
- * @brief       This file contains notification backend definition.
+ * @brief       Definition of NotificationBackend class
  */
 
+#include "NotificationBackend.h"
+
 #include <stdexcept>
-#include <log/alog.h>
+#include <string>
 
-#include "NotificationBackend.h"
+#include <exception/Exception.h>
+#include <log/alog.h>
+#include <socket/Poll.h>
+#include <socket/Socket.h>
+#include <translator/Translator.h>
+#include <config/Path.h>
 
 namespace AskUser {
 
 namespace Agent {
 
-NotificationTalker NotificationBackend::m_notiTalker;
-std::map<RequestId, NotificationBackend *> NotificationBackend::m_idToInstance;
-std::mutex NotificationBackend::m_instanceGuard;
-
-NotificationBackend::NotificationBackend() : m_id(-1), m_isDismissing(false)
-{
-    if (m_notiTalker.isFailed()) {
-        ALOGE("NotificationTalker failed beacause: " << m_notiTalker.getErrorMsg());
-        throw std::runtime_error("Backend failed");
+namespace {
+    UIResponseType NResponseTypeToUI(NResponseType responseType) {
+        switch (responseType) {
+        case NResponseType::Allow:
+            return UIResponseType::URT_YES_LIFE;
+        case NResponseType::Never:
+            return UIResponseType::URT_NO_LIFE;
+        case NResponseType::Error:
+            return UIResponseType::URT_ERROR;
+        case NResponseType::None:
+            return UIResponseType::URT_TIMEOUT;
+        case NResponseType::Deny:
+        default:
+            return UIResponseType::URT_NO_ONCE;
+        }
     }
 }
 
 bool NotificationBackend::start(const std::string &client, const std::string &user,
-                                const std::string &privilege, RequestId requestId,
-                                UIResponseCallback callback)
-{
-    m_idToInstance[requestId] = this;
-    m_id = requestId;
-    m_cb = callback;
-
-    if (m_notiTalker.isFailed()) {
-        ALOGE("NotificationTalker failed beacause: " << m_notiTalker.getErrorMsg());
-        throw std::runtime_error("Backend failed");
+                               const std::string &privilege, RequestId requestId,
+                               UIResponseCallback responseCb) {
+    if (!m_notify.init()) {
+        ALOGW("Couldn't initialize notification object.");
+        return false;
     }
+    m_responseHandler = responseCb;
+    m_request.id = requestId;
+    m_request.data.client = client;
+    m_request.data.user = user;
+    m_request.data.privilege = privilege;
 
-    m_notiTalker.setResponseHandler(&NotificationBackend::responseCb);
-    m_notiTalker.parseRequest(RequestType::RT_Action,
-                              NotificationRequest(requestId, client, user, privilege));
+    m_thread = std::thread(&NotificationBackend::run, this);
     return true;
 }
+bool NotificationBackend::setOutdated() {
+    return false;
+}
+bool NotificationBackend::dismiss() {
+    ALOGD("Dismissing");
+    m_running = false;
+    return m_notify.notify();
+}
+bool NotificationBackend::isDismissing() const {
+    return m_running;
+}
+
+NotificationBackend::~NotificationBackend() {
+    dismiss();
+    m_clientSocket.close();
+    m_thread.join();
+}
 
-void NotificationBackend::responseCb(NotificationResponse response)
+void NotificationBackend::reportError() {
+    m_responseHandler(m_request.id, NResponseTypeToUI(NResponseType::Error));
+}
+
+bool NotificationBackend::sendRequest()
 {
-    std::lock_guard<std::mutex> lock(m_instanceGuard);
-    auto it = m_idToInstance.find(response.id);
-    if (it == m_idToInstance.end()) {
-        ALOGW("Instance for this request does not exist anymore");
-        return;
-    }
-    UIResponseType type;
-    switch(response.response) {
-    case NResponseType::Allow:
-        type = UIResponseType::URT_YES_LIFE;
-        break;
-    case NResponseType::Deny:
-        type = UIResponseType::URT_NO_ONCE;
-        break;
-    case NResponseType::Never:
-        type = UIResponseType::URT_NO_LIFE;
-        break;
-    case NResponseType::Error:
-        type = UIResponseType::URT_ERROR;
-        break;
-    case NResponseType::None:
-        type = UIResponseType::URT_TIMEOUT;
-        break;
-    }
-    it->second->m_cb(response.id, type);
+    std::string data = Translator::Gui::notificationRequestToData(m_request.id,
+                                                                  m_request.data.client,
+                                                                  m_request.data.privilege);
+    return m_clientSocket.send(data);
 }
 
-bool NotificationBackend::setOutdated()
+bool NotificationBackend::parseResponse(NotificationResponse response)
 {
+    if (response.id != m_request.id) {
+        ALOGE("Got response with different id (" << response.id
+              << ") than request (" << m_request.id << ")");
+        return false;
+    }
+
+    ALOGD("For user: <" << m_request.data.user
+          << "> client: <" << m_request.data.client
+          << "> privilege: <" << m_request.data.privilege
+          << "> received: <" << Translator::Gui::responseToString(response.response) << ">");
+
     return true;
 }
 
-bool NotificationBackend::dismiss()
+bool NotificationBackend::recvResponse(NotificationResponse &response)
 {
-    m_notiTalker.parseRequest(RequestType::RT_Cancel, NotificationRequest(m_id));
+    int requestId, responseType;
+    if (!m_clientSocket.recv(requestId) || !m_clientSocket.recv(responseType)) {
+        ALOGE("Failed to fetch response");
+        return false;
+    }
+    response.id = static_cast<RequestId>(requestId);
+    response.response = static_cast<NResponseType>(responseType);
     return true;
 }
 
-bool NotificationBackend::isDismissing() const
+void NotificationBackend::run()
 {
-    return m_isDismissing;
+    try {
+        if (!m_clientSocket.connect(Path::getUserSocketPath(m_request.data.user))) {
+            ALOGE("Cannot connect to proper service");
+            reportError();
+            return;
+        }
+
+        if (!mainLoop()) {
+            reportError();
+            return;
+        }
+
+    } catch (const std::exception &e) {
+        ALOGE("Got exception : " << e.what());
+        reportError();
+    } catch (...) {
+        ALOGE("Got unknown exception");
+        reportError();
+    }
 }
 
-NotificationBackend::~NotificationBackend()
-{
-    std::lock_guard<std::mutex> lock(m_instanceGuard);
-    m_idToInstance.erase(m_id);
+bool NotificationBackend::mainLoop() {
+    ALOGD("Notification loop started");
+    m_poller.setEvents(m_clientSocket.getFd(), POLLOUT | POLLERR | POLLHUP);
+    m_poller.setEvents(m_notify.getNotifyFd(), POLLIN);
+    while (!m_running) {
+        int eCount = m_poller.wait();
+        if (eCount == -1) {
+            ALOGE_ERRNO("Polling failed");
+            return false;
+        }
+
+        if (m_poller.getEvents(m_notify.getNotifyFd()) & POLLIN) {
+            ALOGW("Got signal to stop");
+            return true;
+        }
+
+        if (m_poller.getEvents(m_clientSocket.getFd()) & POLLERR) {
+            ALOGE("Error on socket connection");
+            return false;
+        }
+
+        if (m_poller.getEvents(m_clientSocket.getFd()) & POLLHUP) {
+            ALOGE("Service disconnected");
+            return false;
+        }
+
+        if (m_poller.getEvents(m_clientSocket.getFd()) & POLLOUT) {
+            if (!sendRequest()) {
+                ALOGE("Couldn't send request");
+                return false;
+            }
+
+            m_poller.setEvents(m_clientSocket.getFd(), POLLIN | POLLERR);
+            continue;
+        }
+
+        if (m_poller.getEvents(m_clientSocket.getFd()) & POLLIN) {
+            NotificationResponse response;
+            if (!recvResponse(response)) {
+                ALOGE("Couldn't receive response");
+                return false;
+            }
+            if (!parseResponse(response)) {
+                ALOGE("Incorrect response received");
+                return false;
+            }
+            m_responseHandler(m_request.id, NResponseTypeToUI(response.response));
+            return true;
+        }
+    }
+
+    ALOGD("NotificationBackend loop ended");
+    return true;
 }
 
-} //namespace Agent
+} /* namespace Agent */
 
-} //namespace AskUser
+} /* namespace AskUser */
index 6256bf8..cb0975b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2016 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  *  limitations under the License
  */
 /**
- * @file        NotificationBackend.h
+ * @file        src/daemon/NotificationBackend.cpp
  * @author      Zofia Abramowska <z.abramowska@samsung.com>
- * @brief       This file contains notification backend declaration.
+ * @brief       Declaration of NotificationBackend class
  */
 
 #pragma once
 
+#include <atomic>
 #include <functional>
-#include <map>
-#include <memory>
 #include <string>
+#include <thread>
 
-#include <main/Request.h>
-#include <main/NotificationTalker.h>
 #include <ui/AskUIInterface.h>
-
+#include <ui/FdNotifyObject.h>
+#include <socket/Socket.h>
+#include <socket/Poll.h>
 #include <types/NotificationResponse.h>
+#include <types/NotificationRequest.h>
 
 namespace AskUser {
 
 namespace Agent {
 
+typedef std::function<void(NotificationResponse)> ResponseHandler;
+
 class NotificationBackend : public AskUIInterface {
 public:
-    NotificationBackend();
+    NotificationBackend() : m_poller(2), m_clientSocket(Socket::PeerType::CLIENT), m_running(false) {}
     virtual ~NotificationBackend();
 
     virtual bool start(const std::string &client, const std::string &user,
-                       const std::string &privilege, RequestId requestId, UIResponseCallback);
+                       const std::string &privilege, RequestId requestId,
+                       UIResponseCallback responseCb);
     virtual bool setOutdated();
     virtual bool dismiss();
     virtual bool isDismissing() const;
 
-private:
-    static void responseCb(NotificationResponse response);
-    static NotificationTalker m_notiTalker;
-    static std::map<RequestId, NotificationBackend *> m_idToInstance;
-    static std::mutex m_instanceGuard;
+protected:
+    void reportError();
+    bool mainLoop();
+    void run();
+
+    bool sendRequest();
+    bool parseResponse(NotificationResponse response);
+    bool recvResponse(NotificationResponse &response);
 
-    RequestId m_id;
-    UIResponseCallback m_cb;
-    bool m_isDismissing;
+    FdNotifyObject m_notify;
+    UIResponseCallback m_responseHandler;
+    NotificationRequest m_request;
+    Poll m_poller;
+    Socket m_clientSocket;
+    std::thread m_thread;
+    std::atomic<bool> m_running;
 };
 
-    typedef std::unique_ptr<NotificationBackend> NotificationBackendPtr;
-} // namespace Agent
+} /* namespace Agent */
 
-} // namespace AskUser
+} /* namespace AskUser */
index 0883890..c6f6869 100644 (file)
 namespace AskUser {
 namespace Path {
 
+
+
 const std::string &getSocketPath() {
     static std::string socketPath = "/run/askuserd.socket";
     return socketPath;
 }
 
+const std::string userPathFormatPrefix = "/run/user/";
+const std::string userPathFormatSuffix = "/askuser-notification.socket";
+
 std::string getUserSocketPath(uid_t uid) {
-    const std::string userPathFormatPrefix = "/run/user/";
-    const std::string userPathFormatSuffix = "/askuser-notification.socket";
     return userPathFormatPrefix + std::to_string(uid) + userPathFormatSuffix;
+}
 
+std::string getUserSocketPath(const std::string &user) {
+    return userPathFormatPrefix + user + userPathFormatSuffix;
 }
 
 } // namespace Path
index 61aa12e..26426ef 100644 (file)
@@ -29,6 +29,7 @@ namespace Path {
 
 const std::string &getSocketPath();
 std::string getUserSocketPath(uid_t uid);
+std::string getUserSocketPath(const std::string &user);
 
 } // namespace Path
 } // namespace AskUser
index beac3de..4c5b121 100644 (file)
@@ -33,7 +33,7 @@ public:
     void setEvents(int fd, int events);
     void unset(int fd);
     int getEvents(int fd);
-    int wait(int msec);
+    int wait(int msec = -1);
 
 private:
     pollfd *m_fds;
index 01abfb8..7299b5e 100644 (file)
@@ -22,7 +22,6 @@ SET(TESTS_SOURCES
     ${TESTS_PATH}/main.cpp
     ${TESTS_PATH}/common/exception.cpp
     ${TESTS_PATH}/common/translator.cpp
-    ${TESTS_PATH}/daemon/notificationTalker.cpp
 
     ${PROJECT_SOURCE_DIR}/src/common/config/Limits.cpp
     ${PROJECT_SOURCE_DIR}/src/common/config/Path.cpp
@@ -31,7 +30,6 @@ SET(TESTS_SOURCES
     ${PROJECT_SOURCE_DIR}/src/common/socket/Poll.cpp
     ${PROJECT_SOURCE_DIR}/src/common/translator/Translator.cpp
     ${PROJECT_SOURCE_DIR}/src/common/types/AgentErrorMsg.cpp
-    ${PROJECT_SOURCE_DIR}/src/agent/main/NotificationTalker.cpp
    )
 
 ADD_DEFINITIONS(${TESTS_DEP_CFLAGS})
diff --git a/test/daemon/.notificationTalker.cpp.swp b/test/daemon/.notificationTalker.cpp.swp
deleted file mode 100644 (file)
index dd587a5..0000000
Binary files a/test/daemon/.notificationTalker.cpp.swp and /dev/null differ
diff --git a/test/daemon/notificationTalker.cpp b/test/daemon/notificationTalker.cpp
deleted file mode 100644 (file)
index 67ef2eb..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- *  Copyright (c) 2016 Samsung Electronics Co.
- *
- *  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        notificationTalker.cpp
- * @author      Oskar Świtalski <o.switalski@samsung.com>
- * @brief       Tests for NotificationTalker class
- */
-
-#include <fcntl.h>
-#include <memory>
-#include <unistd.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <NotificationTalker.h>
-
-using namespace AskUser::Agent;
-using namespace AskUser;
-
-using::testing::_;
-
-namespace {
-
-class FakeNotificationTalker : public NotificationTalker {
-public:
-    FakeNotificationTalker() {
-        m_responseHandler = [](NotificationResponse){};
-    }
-
-    void addRequest(NotificationRequest &&request) {
-        addRequest_(request);
-    }
-
-    MOCK_METHOD1(addRequest_, void(NotificationRequest));
-    MOCK_METHOD1(removeRequest, void(RequestId));
-    MOCK_METHOD0(stop, void());
-
-    int queueSize() {
-        int sum = 0;
-        for (auto &pair : m_requests) {
-            sum += std::get<1>(pair).size();
-        }
-        return sum;
-    }
-
-    void invokeAdd(NotificationRequest request) {
-        NotificationTalker::addRequest(std::move(request));
-    }
-
-    void invokeRemove(RequestId id) {
-        NotificationTalker::removeRequest(id);
-    }
-
-    int getSockFd() {
-        return m_serverSocket.getFd();
-    }
-
-    void clear() {
-        NotificationTalker::clear();
-    }
-};
-
-} /* namespace */
-
-TEST(NotificationTalker, addRequest) {
-    using testing::Invoke;
-
-    FakeNotificationTalker notificationTalker;
-    cynara_agent_req_id id = 1;
-    std::string user = "user";
-    std::string client = "client";
-    std::string privilege = "privilege";
-
-    NotificationRequest ptr(id, user, client, privilege);
-
-    EXPECT_CALL(notificationTalker, addRequest_(_)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeAdd));
-
-    int requestCountBegin = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Action, ptr);
-    int requestCountEnd = notificationTalker.queueSize();
-
-    ASSERT_EQ(requestCountBegin + 1, requestCountEnd);
-}
-
-TEST(NotificationTalker, addAndRemoveRequest) {
-    using testing::Invoke;
-
-    FakeNotificationTalker notificationTalker;
-    cynara_agent_req_id id = 1;
-    std::string user = "user";
-    std::string client = "client";
-    std::string privilege = "privilege";
-
-    NotificationRequest ptr(id, user, client, privilege);
-    NotificationRequest ptr2(id);
-
-    EXPECT_CALL(notificationTalker, addRequest_(_)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeAdd));
-
-    EXPECT_CALL(notificationTalker, removeRequest(id)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeRemove));
-
-    int requestCountBegin = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Action, ptr);
-    int requestCountAdd = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Cancel, ptr2);
-    int requestCountEnd = notificationTalker.queueSize();
-
-    ASSERT_EQ(requestCountBegin + 1, requestCountAdd);
-    ASSERT_EQ(requestCountBegin, requestCountEnd);
-}
-
-TEST(NotificationTalker, addAndRemoveNonExistingRequest) {
-    using testing::Invoke;
-
-    FakeNotificationTalker notificationTalker;
-    cynara_agent_req_id id = 1;
-    cynara_agent_req_id id2 = 2;
-    std::string user = "user";
-    std::string client = "client";
-    std::string privilege = "privilege";
-
-    NotificationRequest ptr(id, user, client, privilege);
-    NotificationRequest ptr2(id2);
-
-    EXPECT_CALL(notificationTalker, addRequest_(_)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeAdd));
-
-    EXPECT_CALL(notificationTalker, removeRequest(id2)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeRemove));
-
-    int requestCountBegin = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Action, ptr);
-    int requestCountAdd = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Cancel, ptr2);
-    int requestCountEnd = notificationTalker.queueSize();
-
-    ASSERT_EQ(requestCountBegin + 1, requestCountAdd);
-    ASSERT_EQ(requestCountAdd, requestCountEnd);
-}
-
-TEST(NotificationTalker, removeNonExistingRequest) {
-    using testing::Invoke;
-
-    FakeNotificationTalker notificationTalker;
-    cynara_agent_req_id id = 1;
-
-    NotificationRequest ptr(id);
-
-    EXPECT_CALL(notificationTalker, removeRequest(id)).
-            WillOnce(Invoke(&notificationTalker, &FakeNotificationTalker::invokeRemove));
-
-    int requestCountBegin = notificationTalker.queueSize();
-    notificationTalker.parseRequest(RequestType::RT_Cancel, ptr);
-    int requestCountEnd = notificationTalker.queueSize();
-
-    ASSERT_EQ(requestCountBegin, requestCountEnd);
-}
-
-
-TEST(NotificationTalker, closeRequest) {
-    FakeNotificationTalker notificationTalker;
-
-    cynara_agent_req_id id = 1;
-    NotificationRequest ptr(id);
-
-    EXPECT_CALL(notificationTalker, stop());
-    notificationTalker.parseRequest(RequestType::RT_Close, ptr);
-}
-
-TEST(NotificationTalker, closeSocket) {
-    int fd;
-
-    {
-        FakeNotificationTalker notificationTalker;
-        fd = notificationTalker.getSockFd();
-        ASSERT_NE(-1, fcntl(fd, F_GETFL));
-    }
-
-    ASSERT_EQ(-1, fcntl(fd, F_GETFL));
-}