2 * Copyright (c) 2016 Samsung Electronics Co.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 * @file src/daemon/NotificationTalker.cpp
18 * @author Oskar Ĺwitalski <o.switalski@samsung.com>
19 * @brief Definition of NotificationTalker class
22 #include "NotificationTalker.h"
26 #include <cynara-creds-socket.h>
28 #include <exception/ErrnoException.h>
29 #include <exception/CynaraException.h>
31 #include <socket/Socket.h>
32 #include <translator/Translator.h>
33 #include <config/Path.h>
34 #include <types/Protocol.h>
40 NotificationTalker::NotificationTalker()
43 m_select.setTimeout(100);
44 m_sockfd = Socket::listen(Path::getSocketPath().c_str());
47 void NotificationTalker::parseRequest(RequestType type, NotificationRequest request)
50 case RequestType::RT_Close:
51 ALOGD("Close service");
54 case RequestType::RT_Action:
55 ALOGD("Add request: " << request.id);
56 addRequest(std::move(request));
58 case RequestType::RT_Cancel:
59 ALOGD("Cancel request: " << request.id);
60 removeRequest(request.id);
67 void NotificationTalker::addRequest(NotificationRequest &&request)
69 std::lock_guard<std::mutex> lock(m_mutex);
71 auto &queue = m_requests[request.data.user];
72 auto it = std::find_if(queue.begin(), queue.end(),
73 [&request](const NotificationRequest &req){return req.id == request.id;}
76 if (it == queue.end()) {
77 queue.emplace_back(std::move(request));
79 ALOGD("Cynara request already exists");
83 void NotificationTalker::removeRequest(RequestId id)
85 std::lock_guard<std::mutex> lock(m_mutex);
87 for (auto &pair : m_requests) {
88 auto &queue = std::get<1>(pair);
89 auto it = std::find_if(queue.begin(), queue.end(),
90 [&id](const NotificationRequest &req){return req.id == id;}
92 if (it == queue.end()) {
93 ALOGW("Removing non-existent request");
96 if (it == queue.begin()) {
97 auto user = std::get<0>(pair);
98 auto it2 = m_userToFd.find(user);
99 if (it2 != m_userToFd.end())
100 sendDismiss(std::get<1>(*it2));
107 void NotificationTalker::setResponseHandler(ResponseHandler responseHandler)
109 m_responseHandler = responseHandler;
112 void NotificationTalker::stop()
116 for (auto& pair : m_fdStatus) {
117 int fd = std::get<0>(pair);
125 Socket::close(m_sockfd);
129 NotificationTalker::~NotificationTalker()
131 for (auto& pair : m_fdStatus) {
132 int fd = std::get<0>(pair);
136 Socket::close(m_sockfd);
139 void NotificationTalker::sendRequest(int fd, const NotificationRequest &request)
141 m_fdStatus[fd] = false;
143 std::string data = Translator::Gui::notificationRequestToData(request.id,
145 request.data.privilege);
146 auto size = data.size();
148 if (!Socket::send(fd, &size, sizeof(size))) {
153 if (!Socket::send(fd, data.c_str(), size)) {
159 void NotificationTalker::sendDismiss(int fd)
161 if (!m_fdStatus[fd]) {
162 if (!Socket::send(fd, &Protocol::dissmisCode, sizeof(Protocol::dissmisCode))) {
166 m_fdStatus[fd] = true;
170 void NotificationTalker::parseResponse(NotificationResponse response, int fd)
172 auto &queue = m_requests[m_fdToUser[fd]];
174 ALOGD("Request canceled");
175 m_fdStatus[fd] = true;
179 NotificationRequest request = queue.front();
180 if (request.id != response.id) {
181 ALOGD("Request canceled");
182 m_fdStatus[fd] = true;
187 ALOGD("For user: <" << request.data.user
188 << "> client: <" << request.data.client
189 << "> privilege: <" << request.data.privilege
190 << "> received: <" << Translator::Gui::responseToString(response.response) << ">");
192 m_responseHandler(response);
194 if (!Socket::send(fd, &Protocol::ackCode, sizeof(Protocol::ackCode))) {
199 m_fdStatus[fd] = true;
202 void NotificationTalker::recvResponses(int &rv)
204 for (auto pair : m_userToFd) {
206 int fd = std::get<1>(pair);
208 if (m_select.isSet(fd)) {
211 NotificationResponse response;
212 if (Socket::recv(fd, &response, sizeof(response))) {
213 parseResponse(response, fd);
221 void NotificationTalker::newConnection(int &rv)
223 if (m_select.isSet(m_sockfd)) {
225 int fd = Socket::accept(m_sockfd);
227 char *user_c = nullptr;
229 int ret = cynara_creds_socket_get_user(fd, USER_METHOD_DEFAULT,&user_c);
231 std::unique_ptr<char[]> userPtr(user_c);
233 if (ret != CYNARA_API_SUCCESS) {
234 throw CynaraException("cynara_creds_socket_get_user", ret);
236 std::string user = user_c;
238 auto it = m_userToFd.find(user);
239 if (it != m_userToFd.end())
240 remove(std::get<1>(*it));
242 m_userToFd[user] = fd;
243 m_fdToUser[fd] = user;
244 m_fdStatus[fd] = true;
246 ALOGD("Accepted new conection for user: " << user);
254 void NotificationTalker::remove(int fd)
257 auto user = m_fdToUser[fd];
258 m_fdToUser.erase(fd);
259 m_userToFd.erase(user);
260 m_fdStatus.erase(fd);
263 void NotificationTalker::run()
266 ALOGD("Notification loop started");
267 while (!m_stopflag) {
268 m_select.add(m_sockfd);
270 for (auto pair : m_userToFd)
271 m_select.add(std::get<1>(pair));
273 int rv = m_select.exec();
287 std::lock_guard<std::mutex> lock(m_mutex);
288 for (auto pair : m_fdStatus ) {
289 int fd = std::get<0>(pair);
290 bool b = std::get<1>(pair);
291 auto &queue = m_requests[m_fdToUser[fd]];
292 if (b && !queue.empty()) {
293 NotificationRequest request = queue.front();
294 sendRequest(fd, request);
299 ALOGD("NotificationTalker loop ended");
300 } catch (const std::exception &e) {
301 ALOGE("NotificationTalker: " << e.what());
303 ALOGE("NotificationTalker: unknown error");
307 } /* namespace Agent */
309 } /* namespace AskUser */