${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(
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
--- /dev/null
+/*
+ * 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 */
/*
- * 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 */
/*
- * 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 */
/*
- * 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 */
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
const std::string &getSocketPath();
std::string getUserSocketPath(uid_t uid);
+std::string getUserSocketPath(const std::string &user);
} // namespace Path
} // namespace AskUser
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;
${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
${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})
+++ /dev/null
-/*
- * 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(¬ificationTalker, &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(¬ificationTalker, &FakeNotificationTalker::invokeAdd));
-
- EXPECT_CALL(notificationTalker, removeRequest(id)).
- WillOnce(Invoke(¬ificationTalker, &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(¬ificationTalker, &FakeNotificationTalker::invokeAdd));
-
- EXPECT_CALL(notificationTalker, removeRequest(id2)).
- WillOnce(Invoke(¬ificationTalker, &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(¬ificationTalker, &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));
-}