Implement client side asynchronous channel 22/136222/24
authorPiotr Sawicki <p.sawicki2@partner.samsung.com>
Wed, 5 Jul 2017 11:30:43 +0000 (13:30 +0200)
committerPiotr Sawicki <p.sawicki2@partner.samsung.com>
Thu, 6 Jul 2017 16:54:01 +0000 (18:54 +0200)
* Implement an abstract channel and async client/server channels
* Adjust other modules to this new changes

Change-Id: I6788d01a220dfba3eb3ad2226a8a9ee96878153b

20 files changed:
src/client/CMakeLists.txt
src/client/impl/ApiInterfaceImpl.cpp
src/client/impl/ApiInterfaceImpl.h
src/client/impl/ClientCallbacks.cpp [new file with mode: 0644]
src/client/impl/ClientCallbacks.h [new file with mode: 0644]
src/ipc-lib/CMakeLists.txt
src/ipc-lib/ask-user-channel.cpp
src/ipc-lib/ask-user-client-channel.cpp
src/ipc-lib/ask-user-config.cpp
src/ipc-lib/ask-user-config.h
src/ipc-lib/ask-user-server-channel.cpp [new file with mode: 0644]
src/ipc-lib/askuser-notification/ask-user-channel.h [new file with mode: 0644]
src/ipc-lib/askuser-notification/ask-user-client-channel.h
src/ipc-lib/askuser-notification/ask-user-server-channel.h
src/ipc-lib/askuser-notification/ask-user-types.h
src/ipc-lib/askuser-notification/sock-desc.h [new file with mode: 0644]
src/ipc-lib/sock.cpp
src/ipc-lib/test/main.cpp
src/notification-daemon/Logic.cpp
src/notification-daemon/Logic.h

index 3fafb9f..271273c 100644 (file)
@@ -26,6 +26,7 @@ PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_CLIENT_DEP
 INCLUDE_DIRECTORIES(SYSTEM ${ASKUSER_NOTIFICATION_CLIENT_DEP_INCLUDE_DIRS})
 INCLUDE_DIRECTORIES(
     ${ASKUSER_PATH}/common
+    ${ASKUSER_PATH}/ipc-lib
     ${ASKUSER_NOTIFICATION_CLIENT_PATH}/api
     ${ASKUSER_NOTIFICATION_CLIENT_PATH}/impl
     ${ASKUSER_NOTIFICATION_CLIENT_PATH}/include
@@ -34,6 +35,7 @@ INCLUDE_DIRECTORIES(
 SET(ASKUSER_NOTIFICATION_CLIENT_SOURCES
     ${ASKUSER_NOTIFICATION_CLIENT_PATH}/api/askuser-notification-client.cpp
     ${ASKUSER_NOTIFICATION_CLIENT_PATH}/impl/ApiInterfaceImpl.cpp
+    ${ASKUSER_NOTIFICATION_CLIENT_PATH}/impl/ClientCallbacks.cpp
    )
 
 ADD_LIBRARY(
index ce90206..1a3ec91 100644 (file)
  * @brief       The definition of ApiInterfaceImpl.
  */
 
+#include <askuser-notification/ask-user-client-channel.h>
+#include <askuser-notification/ask-user-types.h>
+
+#include "ClientCallbacks.h"
 #include "ApiInterfaceImpl.h"
 
+namespace {
+
+int eventsToAskUserMask(int events)
+{
+    return ((events & ASKUSER_READ_EVENT) ? AskUser::Protocol::FdMask::READ : 0) |
+           ((events & ASKUSER_WRITE_EVENT) ? AskUser::Protocol::FdMask::WRITE : 0);
+}
+
+int askUserMaskToEvents(int mask)
+{
+    return ((AskUser::Protocol::FdMask::READ & mask) ? ASKUSER_READ_EVENT : 0) |
+           ((AskUser::Protocol::FdMask::WRITE & mask) ? ASKUSER_WRITE_EVENT : 0);
+}
+
+askuser_popup_result responseToAskUserPopupResult(int response)
+{
+    switch (response) {
+        case ASKUSER_ALLOW_FOREVER:
+            return ASKUSER_POPUP_RESULT_ALLOW_FOREVER;
+        case ASKUSER_DENY_FOREVER:
+            return ASKUSER_POPUP_RESULT_DENY_FOREVER;
+        case ASKUSER_DENY_ONCE:
+            return ASKUSER_POPUP_RESULT_DENY_ONCE;
+    }
+
+    return ASKUSER_POPUP_RESULT_DENY_ONCE;
+}
+
+} // namespace
+
 namespace AskUser {
 
 namespace Client {
 
 ApiInterfaceImpl::ApiInterfaceImpl(const StatusCallbackClosure &statusClosure)
 : m_statusClosure(statusClosure)
+, m_channel(std::move(Protocol::ClientCallbacksPtr(new ClientCallbacks(this))))
 {
 }
 
 ApiInterfaceImpl::~ApiInterfaceImpl()
 {
-    // TODO
+    for (const auto &closure : m_callbacks) {
+        closure.second(closure.first, askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE,
+                       askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_ONCE);
+    }
 }
 
 int ApiInterfaceImpl::process(int fd, int events)
 {
-    // TODO
-    (void) fd;
-    (void) events;
-    return 0;
+    return m_channel.process(fd, eventsToAskUserMask(events));
 }
 
 askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege)
 {
-    // TODO
+    // TODO use PolicyFetchRequest
     (void) privilege;
 
     return ASKUSER_CHECK_RESULT_DENY;
@@ -56,11 +91,48 @@ askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privile
 RequestId ApiInterfaceImpl::popupRequest(const PopupCallbackClosure &closure,
                                          const std::string &privilege)
 {
-    // TODO
-    (void) closure;
-    (void) privilege;
+    Client::RequestId id = static_cast<Client::RequestId>(m_channel.popupRequest(privilege));
+
+    auto it = m_callbacks.find(id);
+    if (it != m_callbacks.end()) {
+        it->second(it->first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
+        m_callbacks.erase(it);
+    }
+
+    m_callbacks.insert({id, closure});
+
+    return id;
+}
+
+void ApiInterfaceImpl::updateConnection(Protocol::ConnectionFd fd, int mask)
+{
+    m_statusClosure(fd, askUserMaskToEvents(mask));
+
+    // remove all pending events
+    if (mask == ASKUSER_EMPTY_EVENTS) {
+        for (const auto &closure : m_callbacks) {
+            closure.second(closure.first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
+        }
+
+        m_callbacks.clear();
+    }
+}
+
+void ApiInterfaceImpl::popupResponse(Protocol::RequestId id, int response)
+{
+    auto it = m_callbacks.find(id);
+    if (it == m_callbacks.end()) {
+        return;
+    }
+
+    askuser_call_cause cause = ASKUSER_CALL_CAUSE_ANSWER;
+    if (response == ASKUSER_UNKNOWN_ERROR) {
+        cause = ASKUSER_CALL_CAUSE_ERROR;
+    }
 
-    return 0;
+    askuser_popup_result res = responseToAskUserPopupResult(response);
+    it->second(id, cause, res);
+    m_callbacks.erase(it);
 }
 
 } // namespace Client
index e255ac2..0b45410 100644 (file)
 
 #pragma once
 
+#include <memory>
+
 #include <ApiInterface.h>
 #include <PopupCallbackClosure.h>
 #include <StatusCallbackClosure.h>
 
+#include <askuser-notification/ask-user-client-channel.h>
+
 #include <askuser-notification-client.h>
 
 namespace AskUser {
 
 namespace Client {
 
-class ApiInterfaceImpl : public AskUser::Client::ApiInterface {
+class ApiInterfaceImpl : public ApiInterface {
 public:
-    ApiInterfaceImpl(const AskUser::Client::StatusCallbackClosure &closure);
+    ApiInterfaceImpl(const StatusCallbackClosure &closure);
     ApiInterfaceImpl(const ApiInterfaceImpl& orig) = delete;
     virtual ~ApiInterfaceImpl();
 
@@ -43,11 +47,16 @@ public:
 
     virtual int process(int fd, int events);
     virtual askuser_check_result checkPrivilege(const std::string &privilege);
-    virtual RequestId popupRequest(const AskUser::Client::PopupCallbackClosure &closure,
+    virtual RequestId popupRequest(const PopupCallbackClosure &closure,
                                    const std::string &privilege);
 
+    void updateConnection(Protocol::ConnectionFd fd, int mask);
+    void popupResponse(Protocol::RequestId id, int response);
+
 private:
-    AskUser::Client::StatusCallbackClosure m_statusClosure;
+    StatusCallbackClosure m_statusClosure;
+    Protocol::ClientChannel m_channel;
+    std::map<RequestId, PopupCallbackClosure> m_callbacks;
 };
 
 } // namespace Client
diff --git a/src/client/impl/ClientCallbacks.cpp b/src/client/impl/ClientCallbacks.cpp
new file mode 100644 (file)
index 0000000..84705d4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2017 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        ClientCallbacks.cpp
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @version     1.0
+ * @brief       The definition of ClientCallbacks.
+ */
+
+#include "ClientCallbacks.h"
+
+namespace AskUser {
+
+namespace Client {
+
+void ClientCallbacks::updateConnection(Protocol::ConnectionFd fd, int mask)
+{
+    m_api->updateConnection(fd, mask);
+}
+
+void ClientCallbacks::popupResponse(Protocol::RequestId id, int response)
+{
+    m_api->popupResponse(id, response);
+}
+
+} // namespace Client
+
+} // namespace AskUser
diff --git a/src/client/impl/ClientCallbacks.h b/src/client/impl/ClientCallbacks.h
new file mode 100644 (file)
index 0000000..440bde1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2017 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        ClientCallbacks.h
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @version     1.0
+ * @brief       The declaration of ClientCallbacks.
+ */
+
+#pragma once
+
+#include <askuser-notification/ask-user-client-channel.h>
+
+#include "ApiInterfaceImpl.h"
+
+namespace AskUser {
+
+namespace Client {
+
+class ClientCallbacks : public Protocol::IClientCallbacks {
+public:
+
+    ClientCallbacks(ApiInterfaceImpl *api) : m_api(api)
+    {}
+
+    virtual void updateConnection(Protocol::ConnectionFd fd, int mask);
+    virtual void popupResponse(Protocol::RequestId id, int response);
+
+private:
+    ApiInterfaceImpl *m_api;
+};
+
+} // namespace Client
+
+} // namespace AskUser
index 7a14619..78899a4 100644 (file)
@@ -25,12 +25,14 @@ PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_LIB_DEP
 
 INCLUDE_DIRECTORIES(SYSTEM ${ASKUSER_NOTIFICATION_LIB_DEP_INCLUDE_DIRS})
 INCLUDE_DIRECTORIES(
+    ${ASKUSER_PATH}/common
     ${ASKUSER_NOTIFICATION_LIB_PATH}
   )
 
 SET(ASKUSER_NOTIFICATION_LIB_SOURCES
     ${ASKUSER_NOTIFICATION_LIB_PATH}/ask-user-channel.cpp
     ${ASKUSER_NOTIFICATION_LIB_PATH}/ask-user-client-channel.cpp
+    ${ASKUSER_NOTIFICATION_LIB_PATH}/ask-user-server-channel.cpp
     ${ASKUSER_NOTIFICATION_LIB_PATH}/sock.cpp
     ${ASKUSER_NOTIFICATION_LIB_PATH}/ask-user-config.cpp
    )
@@ -53,7 +55,12 @@ SET_TARGET_PROPERTIES(${TARGET_ASKUSER_NOTIFICATION_LIB}
 
 LINK_DIRECTORIES(${ASKUSER_NOTIFICATION_LIB_DEP_LIBRARY_DIRS})
 
-TARGET_LINK_LIBRARIES(${TARGET_ASKUSER_NOTIFICATION_LIB} ${ASKUSER_NOTIFICATION_LIB_DEP_LIBRARIES})
+TARGET_LINK_LIBRARIES(
+    ${TARGET_ASKUSER_NOTIFICATION_LIB}
+    ${TARGET_ASKUSER_COMMON}
+    ${ASKUSER_NOTIFICATION_LIB_DEP_LIBRARIES}
+   )
+
 TARGET_LINK_LIBRARIES(${TARGET_ASKUSER_NOTIFICATION_LIB_TEST} ${TARGET_ASKUSER_NOTIFICATION_LIB})
 
 INSTALL(TARGETS     ${TARGET_ASKUSER_NOTIFICATION_LIB}
index 5b7c9f5..e59d0bf 100644 (file)
  *  limitations under the License
  */
 /**
- * @file        channel.cpp
+ * @file        ask-user-channel.cpp
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @autor       Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @autor       Rafal Krypa <r.krypa@samsung.com>
+ * @brief       The implementation of Channel.
  */
 
-#include <cstdlib>
-#include <string>
-#include <sstream>
-
-#include <askuser-notification/ask-user-server-channel.h>
-#include <askuser-notification/sock.h>
+#include <log/alog.h>
+#include <askuser-notification/sock-desc.h>
+#include <askuser-notification/ask-user-channel.h>
 
 #include <ask-user-config.h>
-#include <ask-user-channel.h>
 
 namespace AskUser {
 namespace Protocol {
 
-void Channel::init() {
-    Sock stream(Sock::SRV_STREAM);
-    stream.connect(getStreamSocketPath(getuid()));
-
-    int fd = stream.getFd();
-    m_sockets[fd] = SockDesc(std::move(stream));
-
-    m_callbacks->updateConnection(fd, FdMask::READ);
-}
-
-void Channel::parse(const std::string &data, std::vector<std::string> &parsedData)
-{
-    size_t begin = 0;
-
-    while (begin < data.size()) {
-        size_t end = data.find(' ', begin);
-
-        if (end == std::string::npos) {
-            parsedData.push_back(data.substr(begin));
-            return;
-        }
-
-        parsedData.push_back(data.substr(begin, end - begin));
-        begin = end + 1;
-    }
-}
-
-void Channel::process(int fd, int mask) {
+int Channel::process(int fd, int mask) {
     try {
         auto it = m_sockets.find(fd);
-        if (it == m_sockets.end())
-            return;
+        if (it == m_sockets.end()) {
+            ALOGE("Cannot find file descriptor " << fd);
+            return -EBADF;
+        }
 
         if (0 == mask) {
-            m_callbacks->updateConnection(fd, 0);
+            onClose(fd);
             m_sockets.erase(it);
-            return;
+            ALOGD("Closing connection on file descriptor: " << fd);
+            return -ENOTCONN;
         }
 
         auto &desc = it->second;
@@ -76,42 +50,46 @@ void Channel::process(int fd, int mask) {
         if (desc.sock.getType() == Sock::SRV_STREAM) {
             Sock client = desc.sock.accept();
             int fd = client.getFd();
-            if (fd < 0)
-                return;
+            if (fd < 0) {
+                ALOGE("Cannot accept a connection on file descriptor: " << desc.sock.getFd());
+                return -EBADF;
+            }
             m_sockets[fd] = SockDesc(std::move(client));
-            m_callbacks->newConnection(fd, Credentials());
-            m_callbacks->updateConnection(fd, FdMask::READ);
-            return;
+            onAccept(fd);
+            return 0;
         }
 
         if (mask & FdMask::READ) {
             int ret = desc.sock.recv(desc.input);
 
             if (ret <= 0) {
-                m_callbacks->updateConnection(fd, 0);
+                onClose(fd);
                 m_sockets.erase(fd);
-                return;
+                ALOGE("Cannot read a message from file descriptor: " << fd);
+                return -ENOTCONN;
             }
 
-            std::vector<std::string> params;
-            parse(std::string(desc.input.begin(), desc.input.end()), params);
-            desc.input.clear();
+            // TODO framing
+            // check that we have the whole message
+            // only then we can extract and parse it
 
-            int command = std::stoi(params[0]);
+            // TODO assume that the message is limited in size
+            // A malicious user can try to allocate memory as much as he or she can.
+            // After detecting such a situation just close a socket.
 
+            std::vector<std::string> message;
+            parse(std::string(desc.input.begin(), desc.input.end()), message);
 
-            switch (command) {
-            case MSGID_POPUP:
-                {
-                    std::string &privilege = params[1];
-                    RequestId id = std::strtol(params[2].c_str(), nullptr, 10);
-                    m_callbacks->popup(fd, id, std::move(privilege));
-                    break;
-                }
-            default :
-                // TODO log the error
-                m_callbacks->updateConnection(fd, 0);
+            // TODO don't clear the buffer, maybe there are some characters
+            // belonging to the next message
+            desc.input.clear();
+
+            int status = onReceive(fd, std::move(message));
+            if (status < 0) {
+                onClose(fd);
                 m_sockets.erase(fd);
+                ALOGE("Problem while processing received message for file descriptor: " << fd);
+                return -ENOTCONN;
             }
         }
 
@@ -119,53 +97,44 @@ void Channel::process(int fd, int mask) {
             int size = static_cast<int>(desc.output.size());
             int result = desc.sock.send(desc.output);
             if (result < 0) {
-                m_callbacks->updateConnection(fd, 0);
+                onClose(fd);
                 m_sockets.erase(fd);
-                return;
+                ALOGE("Cannot send a message on file descritptor: " << fd);
+                return -ENOTCONN;
             }
 
             if (result == size) {
                 desc.output.clear();
-                m_callbacks->updateConnection(fd, FdMask::READ);
+                onSend(fd);
             }
 
             if (result < size) {
                 desc.output.erase(desc.output.begin(), desc.output.begin()+result);
             }
         }
-    } catch (const std::exception &){
+    } catch (const std::exception &e){
         // TODO handle error
+        ALOGE("Unhandled exception occured while processing file descriptor: " << fd);
+        return -ENOTCONN;
     }
-}
 
-void Channel::popupResponse(ConnectionFd fd, RequestId id, int response) {
-    try {
-        auto it = m_sockets.find(fd);
-        if (it == m_sockets.end())
-            return;
+    return 0;
+}
 
-        auto &desc = it->second;
+void Channel::parse(const std::string &data, std::vector<std::string> &parsedData)
+{
+    size_t begin = 0;
 
-        std::stringstream ss;
-        ss << id << " " << response;
-        std::string o = ss.str();
-        std::copy(o.begin(), o.end(), std::back_inserter(desc.output));
-        m_callbacks->updateConnection(fd, FdMask::READ | FdMask::WRITE);
-    } catch (const std::exception &){}
-}
+    while (begin < data.size()) {
+        size_t end = data.find(' ', begin);
 
-Channel::~Channel() {
-    for (auto &e : m_sockets)
-        m_callbacks->updateConnection(e.first, 0);
-}
+        if (end == std::string::npos) {
+            parsedData.push_back(data.substr(begin));
+            return;
+        }
 
-ChannelPtr createChannel(ServerCallbacksPtr ptr) {
-    try {
-        Channel *c = new Channel(std::move(ptr));
-        c->init();
-        return ChannelPtr(c);
-    } catch (const std::exception &) {
-        return ChannelPtr(nullptr);
+        parsedData.push_back(data.substr(begin, end - begin));
+        begin = end + 1;
     }
 }
 
index 61ba65e..a59da5c 100644 (file)
  *  limitations under the License
  */
 /**
- * @file        ipc-client.cpp
+ * @file        ask-user-client-channel.cpp
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The implementation of ClientChannel.
  */
+#include <iostream>
 #include <sstream>
-#include <string>
-#include <vector>
-#include <memory>
 
+#include <attributes/attributes.h>
 #include <askuser-notification/ask-user-client-channel.h>
-#include <askuser-notification/ask-user-server-channel.h>
-#include <askuser-notification/sock.h>
 
 #include <ask-user-config.h>
 
-#define UNUSED __attribute__((unused))
-
 namespace AskUser {
 namespace Protocol {
 
-int popup_launch(const std::string &pkgName,
-                 const std::string &appName,
-                 uid_t uid,
-                 const PrivilegeVector &privileges,
-                 int &result)
-{
-    try {
-        Sock s(Sock::CLI_STREAM);
-        if (0 > s.connect(getStreamSocketPath(uid)))
-            return -1;
-
-        std::stringstream ss;
-        ss << MSGID_POPUP << " " << pkgName << " " << appName << " " << uid;
-        for (auto &e : privileges) {
-            ss << " " << e;
-        }
+ClientChannel::ClientChannel(ClientCallbacksPtr ptr)
+  : m_callbacks(std::move(ptr)) {
+}
 
-        std::string str = ss.str();
+ClientChannel::~ClientChannel() {
+    for (auto &e : m_sockets) {
+        onClose(e.first);
+    }
+}
 
-        if (0 > s.send(RawBuffer(str.begin(), str.end())))
-            return -1;
+void ClientChannel::init() {
+    Sock s(Sock::CLI_STREAM);
+    if (0 > s.connect(getStreamSocketPath(geteuid())))
+        throw std::logic_error("Cannot connect to the server");
 
-        RawBuffer resp;
-        if (0 > s.wait(FdMask::READ))
-            return -1;
-        if (0 > s.recv(resp))
-            return -1;
+    int fd = s.getFd();
+    m_sockets[fd] = SockDesc(std::move(s));
+}
 
-        std::string input(resp.begin(), resp.end());
-        std::stringstream sss(input);
-        sss >> result;
+AskUser::Protocol::RequestId ClientChannel::generateRequestId() {
+    static RequestId requestId = 0;
+    return requestId++;
+}
 
-        return 0;
-    } catch (const std::exception &) {
-        return -1;
+Protocol::RequestId ClientChannel::popupRequest(const std::string &privilege) {
+    if (m_sockets.empty()) {
+        init();
     }
-}
 
-int popup_runtime(UNUSED const std::string &pkgName,
-                  UNUSED const std::string &appName,
-                  UNUSED uid_t uid,
-                  UNUSED std::string &privilege,
-                  UNUSED int &result)
-{
-    return -1;
-}
+    std::stringstream ss;
+    RequestId requestId = generateRequestId();
+    // TODO base64 encode privilege, use g_base64_encode()
+    ss << MSGID_POPUP << " " << privilege << " " << requestId;
+    // client uses only one active socket
+    int fd = m_sockets.begin()->first;
+    std::string str = ss.str();
+    std::copy(str.begin(), str.end(), std::back_inserter(m_sockets[fd].output));
 
+    m_callbacks->updateConnection(fd, FdMask::READ | FdMask::WRITE);
 
-int toast_deny(const std::string &pkgName,
-               const std::string &appName,
-               uid_t uid,
-               const std::string &privilege)
-{
-    try {
-        Sock s(Sock::CLI_DGRAM);
-        if (0 > s.connect(getDatagramSocketPath(uid)))
-            return -1;
+    return requestId;
+}
 
-        std::string str = std::to_string(MSGID_TOAST1) + " " + pkgName + " " + appName + " " + std::to_string(uid) + " " + privilege;
+void ClientChannel::onAccept(int) {
+}
 
-        return s.send(RawBuffer(str.begin(), str.end()));
-    } catch (const std::exception &) {
-        return -1;
-    }
+void ClientChannel::onClose(int fd) {
+    m_callbacks->updateConnection(fd, 0);
 }
 
-int toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid) {
-    try {
-        Sock s(Sock::CLI_DGRAM);
-        if (0 > s.connect(getDatagramSocketPath(uid)))
-            return -1;
+int ClientChannel::onReceive(UNUSED int fd, std::vector<std::string> &&message) {
+    if (!message.size())
+        return -EINVAL;
 
-        std::string str = std::to_string(MSGID_TOAST2) + " " + pkgName + " " + appName + " " + std::to_string(uid);
+    int command = std::stoi(message[0]);
 
-        return s.send(RawBuffer(str.begin(), str.end()));
-    } catch (const std::exception &) {
-        return -1;
+    switch (command) {
+    case MSGID_POPUP_RESPONSE:
+        {
+            if (message.size() != 3)
+                return -EINVAL;
+
+            RequestId id = std::strtol(message[1].c_str(), nullptr, 10);
+            int response = std::strtol(message[2].c_str(), nullptr, 10);
+            m_callbacks->popupResponse(id, response);
+            break;
+        }
+    default :
+        return -EINVAL;
     }
+
+    return 0;
+}
+
+void ClientChannel::onSend(int fd) {
+    m_callbacks->updateConnection(fd, FdMask::READ);
 }
 
 } // namespace Protocol
 } // namespace AskUser
 
-
index 19f9364..597abe6 100644 (file)
@@ -16,7 +16,7 @@
 /**
  * @file        ask-user-config.cpp
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @brief       The implementation of utility functions for getting sockets paths.
  */
 #include <ask-user-config.h>
 
index 7b77be4..e6ed815 100644 (file)
 /**
  * @file        ask-user-config.h
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @brief       The declaration of utility functions for getting sockets paths.
  */
 #pragma once
 
 #include <string>
 #include <sys/types.h>
 
-// We want to use it constat expressions (this is the reason why it's not in cpp file
-const int MSGID_POPUP = 1;
-const int MSGID_TOAST1 = 2;
-const int MSGID_TOAST2 = 3;
-
 std::string getDatagramSocketPath(uid_t uid);
 std::string getStreamSocketPath(uid_t uid);
 
diff --git a/src/ipc-lib/ask-user-server-channel.cpp b/src/ipc-lib/ask-user-server-channel.cpp
new file mode 100644 (file)
index 0000000..ba72edb
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2017 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        ask-user-server-channel.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The implementation of ServerChannel.
+ */
+#include <iostream>
+#include <sstream>
+
+#include <askuser-notification/ask-user-server-channel.h>
+
+#include <ask-user-config.h>
+
+namespace AskUser {
+namespace Protocol {
+
+ServerChannel::ServerChannel(ServerCallbacksPtr ptr)
+  : m_callbacks(std::move(ptr))
+{
+      init();
+}
+
+ServerChannel::~ServerChannel() {
+    for (auto &e : m_sockets) {
+        onClose(e.first);
+    }
+}
+
+void ServerChannel::init() {
+    Sock stream(Sock::SRV_STREAM);
+    stream.connect(getStreamSocketPath(geteuid()));
+
+    int fd = stream.getFd();
+    m_sockets[fd] = SockDesc(std::move(stream));
+
+    m_callbacks->updateConnection(fd, FdMask::READ);
+}
+
+void ServerChannel::popupResponse(ConnectionFd fd, RequestId id, int response) {
+    try {
+        auto it = m_sockets.find(fd);
+        if (it == m_sockets.end())
+            return;
+
+        auto &desc = it->second;
+
+        std::stringstream ss;
+        ss << MSGID_POPUP_RESPONSE << " " << id << " " << response;
+        std::string o = ss.str();
+        std::copy(o.begin(), o.end(), std::back_inserter(desc.output));
+
+        m_callbacks->updateConnection(fd, FdMask::READ | FdMask::WRITE);
+    } catch (const std::exception &){}
+}
+
+void ServerChannel::onAccept(int fd) {
+    m_callbacks->newConnection(fd, Credentials());
+    m_callbacks->updateConnection(fd, FdMask::READ);
+}
+
+void ServerChannel::onClose(int fd) {
+    m_callbacks->updateConnection(fd, 0);
+}
+
+int ServerChannel::onReceive(int fd, std::vector<std::string> &&message) {
+    if (!message.size())
+        return -1;
+
+    int command = std::stoi(message[0]);
+
+    switch (command) {
+    case MSGID_POPUP:
+        {
+            if (message.size() != 3)
+                return -1;
+
+            std::string &privilege = message[1];
+            RequestId requestId = std::strtol(message[2].c_str(), nullptr, 10);
+            // TODO base64 decode privilege. Privilege may contain
+            // any character: \n, space, etc. use g_base64_decode()
+            m_callbacks->popup(fd, requestId, std::move(privilege));
+            break;
+        }
+    default :
+        return -1;
+    }
+
+    return 0;
+}
+
+void ServerChannel::onSend(int fd) {
+    m_callbacks->updateConnection(fd, FdMask::READ);
+}
+
+} // namespace Protocol
+} // namespace AskUser
diff --git a/src/ipc-lib/askuser-notification/ask-user-channel.h b/src/ipc-lib/askuser-notification/ask-user-channel.h
new file mode 100644 (file)
index 0000000..7bd3658
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2017 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        ask-user-channel.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The declaration of Channel.
+ */
+#pragma once
+
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <askuser-notification/sock-desc.h>
+#include <askuser-notification/ask-user-types.h>
+
+namespace AskUser {
+namespace Protocol {
+
+/**
+ * An abstract channel.
+ */
+class Channel {
+public:
+
+    virtual ~Channel() {};
+
+    /**
+     * Process function should be called each time some event is reported by poll/select on
+     * descriptor.
+     *
+     * \param[in] fd    Number of descriptor.
+     * \param[in] mask  Information about event that is waiting on descriptor
+     *                  (FdMask::READ or FdMask::WRITE). If you pass 0 for some reason
+     *                  the descriptor will be closed and callback updateFd will be called
+     *                  with mask = 0
+     * \return          0 on success
+     * \return          a negative value in case of an error (see errno)
+     */
+    virtual int process(int fd, int mask);
+
+    virtual void onAccept(int fd) = 0;
+    virtual void onClose(int fd) = 0;
+    virtual int onReceive(int fd, std::vector<std::string> &&params) = 0;
+    virtual void onSend(int fd) = 0;
+
+protected:
+    void parse(const std::string &data, std::vector<std::string> &parsedData);
+
+    SocketMap m_sockets;
+};
+
+} // namespace Protocol
+} // namespace AskUser
index a98602f..294bdb2 100644 (file)
 /**
  * @file        ask-user-client.h
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The declaration of IClientCallbacks and ClientChannel.
  */
 #pragma once
 
-#include <sys/types.h>
-
+#include <memory>
 #include <string>
 #include <vector>
-#include <memory>
+
+#include <askuser-notification/ask-user-channel.h>
 #include <askuser-notification/ask-user-types.h>
 
 namespace AskUser {
 namespace Protocol {
+
 /**
- * Synchronous request for showing popup.
- *
- * \param[in] pkgName    Application package name.
- * \param[in] appName    Application name.
- * \param[in] uid        Information about user that should see popup.
- * \param[in] privileges List of privileges that should be shown to user.
- * \param[out] result    Result returned by ask-user application.
- *
- * \return Value less that 0 means ipc error.
+ * IServiceCallbacks defines set of callbacks that must be implemented in client.
  */
- int popup_launch(const std::string &pkgName, const std::string &appName, uid_t uid, const PrivilegeVector &privileges, int &result);
+struct IClientCallbacks {
 
- /**
-  * Synchronous request for showing popup.
-  *
-  * \param[in] pkgName    Application package name.
-  * \param[in] appName    Application name.
-  * \param[in] uid        Information about user that should see popup.
-  * \param[in] privilege  Privilege that should be shown to user.
-  * \param[out] result    Result returned by ask-user application.
-  *
-  * \return Value less that 0 means ipc error.
-  */
- int popup_runtime(const std::string &pkgName, const std::string &appName, uid_t uid, std::string &privilege, int &result);
+    virtual ~IClientCallbacks(){}
 
-/**
* Nonblocking request for showing toast.
- *
- * \param[in] pkgName    Application package name.
* \param[in] appName    Application name.
- * \param[in] uid        Information about user that should see popup.
- * \param[in] privilege  Name of privilege that was denied.
- *
- * \return Value less that 0 means ipc error.
- */
-int toast_deny(const std::string &pkgName, const std::string &appName, uid_t uid, const std::string &privilege);
+    /**
    * This function gives you number of descriptor that should be watched by poll/select.
    *
+     * \param[in] fd Connection file descriptor
    * \param[in] mask Type of acction that is required on this descriptor.
+     *            mask == 0 remove descriptor fd from watched pool
+     *            mask == 1 watch descriptor for READ
+     *            mask == 2 watch descriptor for WRITE
+     *            maks == 3 watch descriptor for READ and WRITE
    */
+    virtual void updateConnection(ConnectionFd fd, int mask) = 0;
 
-/**
- * Nonblocking request for showing toast.
- *
- * \param[in] pkgName    Application package name.
- * \param[in] appName    Application name.
- * \param[in] uid        Information about user that should see popup.
- *
- * \return Value less that 0 means ipc error.
- */
-int toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid);
+    /**
+     * This function is called when popup response is received.
+     *
+     * \param[in] id Request identifier
+     * \param[in] response Response from popup
+     */
+    virtual void popupResponse(RequestId id, int response) = 0;
+};
+
+typedef std::unique_ptr<IClientCallbacks> ClientCallbacksPtr;
+
+class ClientChannel : public Channel {
+public:
+    ClientChannel(ClientCallbacksPtr ptr);
+    virtual ~ClientChannel();
+
+    virtual Protocol::RequestId popupRequest(const std::string &privilege);
+
+    virtual void onAccept(int fd);
+    virtual void onClose(int fd);
+    virtual int onReceive(int fd, std::vector<std::string> &&message);
+    virtual void onSend(int fd);
+
+private:
+    void init();
+    AskUser::Protocol::RequestId generateRequestId();
+
+    ClientCallbacksPtr m_callbacks;
+};
 
 } // namespace Protocol
 } // namespace AskUser
index ca55528..c5987ce 100644 (file)
  *  limitations under the License
  */
 /**
- * @file        ask-user-service.h
+ * @file        ask-user-server.h
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The declaration of IServerCallbacks and ServerChannel.
  */
 #pragma once
 
-#include <sys/types.h>
-
+#include <memory>
 #include <string>
 #include <vector>
-#include <memory>
 
 #include <askuser-notification/ask-user-types.h>
+#include <askuser-notification/ask-user-channel.h>
 
 namespace AskUser {
 namespace Protocol {
 
-typedef int ConnectionFd;
-typedef int RequestId;
-
-const ConnectionFd INVALID_FD = -1;
-const RequestId INVALID_ID = -1;
-
-enum FdMask {
-    READ = 1,
-    WRITE = 2,
-};
-
-struct Credentials {
-    std::string label;
-    uid_t uid;
-};
-
 /**
- * IServiceCallbacks defines set of callbacks that must be implemented in service.
+ * IServiceCallbacks defines set of callbacks that must be implemented in server.
  */
-
 struct IServerCallbacks {
 
     virtual ~IServerCallbacks(){}
@@ -59,6 +42,7 @@ struct IServerCallbacks {
      * Fd is file descriptor for this new peer connection.
      *
      * \param[in] fd Connection file descriptor
+     * \param[in] creds Credentials taken from the file descriptor
      */
     virtual void newConnection(ConnectionFd fd, const Credentials &creds) = 0;
 
@@ -67,10 +51,10 @@ struct IServerCallbacks {
      *
      * \param[in] fd Connection file descriptor
      * \param[in] mask Type of acction that is required on this descriptor.
-     *           mask == 0 remove descriptor fd from watched pool
-     *           mask == 1 watch descriptor for READ
-     *           mask == 2 watch descriptor for WRITE
-     *           maks == 3 watch descriptor for READ and WRITE
+     *                 mask == 0 remove descriptor fd from watched pool
+     *                 mask == 1 watch descriptor for READ
+     *                 mask == 2 watch descriptor for WRITE
+     *                 mask == 3 watch descriptor for READ and WRITE
      */
     virtual void updateConnection(ConnectionFd fd, int mask) = 0;
 
@@ -84,35 +68,25 @@ struct IServerCallbacks {
     virtual void popup(ConnectionFd fd, RequestId id, std::string &&privilege) = 0;
 };
 
-struct IChannel {
-    virtual ~IChannel(){}
+typedef std::unique_ptr<IServerCallbacks> ServerCallbacksPtr;
+
+class ServerChannel : public Channel {
+public:
+    ServerChannel(ServerCallbacksPtr ptr);
+    virtual ~ServerChannel();
 
-    /**
-     * Process function should be called each time some event is reported by poll/select on
-     * descriptor.
-     *
-     * \param[in] fd    Number of descriptor.
-     * \param[in] mask  Information about event that is waiting on descriptor
-     *                 (FdMask::READ or FdMask::WRITE). If you pass 0 for some reason
-     *                 the descriptor will be closed and callback updateFd will be called
-     *                 with mask = 0
-     */
-    virtual void process(int fd, int mask) = 0;
+    virtual void popupResponse(ConnectionFd fd, RequestId id, int response);
 
-    /**
-     * Information about action that was chosen by user.
-     *
-     * \param[in] requestId  Request number.
-     * \param[in] response   Information about action chosen by user.
-     */
-    virtual void popupResponse(ConnectionFd fd, RequestId id, int response) = 0;
-};
+    virtual void onAccept(int fd);
+    virtual void onClose(int fd);
+    virtual int onReceive(int fd, std::vector<std::string> &&message);
+    virtual void onSend(int fd);
 
-typedef std::unique_ptr<IChannel> ChannelPtr;
-typedef std::unique_ptr<IServerCallbacks> ServerCallbacksPtr;
+private:
+    void init();
 
-ChannelPtr createChannel(ServerCallbacksPtr ptr);
+    ServerCallbacksPtr m_callbacks;
+};
 
 } // namespace Protocol
 } // namespace AskUser
-
index 8641df3..71ab50c 100644 (file)
 /**
  * @file        ask-user-types.h
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief
+ * @brief       The declaration of various types used by the library.
  */
 #pragma once
 
+#include <map>
+#include <string>
+#include <vector>
+
 #define ASKUSER_NONE 0
 #define ASKUSER_DENY_ONCE 1
 #define ASKUSER_DENY_FOREVER 2
 namespace AskUser {
 namespace Protocol {
 
+enum FdMask {
+    READ = 1,
+    WRITE = 2,
+};
+
+struct Credentials {
+    std::string label;
+    uid_t uid;
+};
+
+typedef int ConnectionFd;
+typedef int RequestId;
 typedef std::string Privilege;
 typedef std::vector<Privilege> PrivilegeVector;
 
+const ConnectionFd INVALID_FD = -1;
+const RequestId INVALID_ID = -1;
+
+// We want to use it constat expressions (this is the reason why it's not in cpp file)
+const int MSGID_POPUP = 1;
+const int MSGID_TOAST1 = 2;
+const int MSGID_TOAST2 = 3;
+const int MSGID_POPUP_RESPONSE = 1;
+
 } // namespace Protocol
 } // AskUser
-
diff --git a/src/ipc-lib/askuser-notification/sock-desc.h b/src/ipc-lib/askuser-notification/sock-desc.h
new file mode 100644 (file)
index 0000000..ebdc5cd
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2017 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        sock-desc.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @autor       Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @brief       The declaration of SockDesc.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <askuser-notification/sock.h>
+#include <askuser-notification/raw-buffer.h>
+
+namespace AskUser {
+namespace Protocol {
+
+struct SockDesc {
+    SockDesc(Sock psock)
+      : sock(std::move(psock))
+    {}
+    SockDesc(){}
+    Sock sock;
+    RawBuffer input;
+    RawBuffer output;
+};
+
+typedef std::map<int, SockDesc> SocketMap;
+
+} // namespace Protocol
+} // namespace AskUser
index a2ec49a..fccce16 100644 (file)
@@ -14,9 +14,9 @@
  *  limitations under the License
  */
 /**
- * @file        Sock.cpp
+ * @file        sock.cpp
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
- * @brief       Implementation of Sock methods
+ * @brief       The implementation of Sock.
  */
 #include <poll.h>
 #include <stdexcept>
@@ -31,7 +31,7 @@
 #include <string>
 #include <vector>
 
-#include <askuser-notification/ask-user-server-channel.h>
+#include <askuser-notification/ask-user-types.h>
 #include <askuser-notification/sock.h>
 
 namespace AskUser {
index b73de55..48f1457 100644 (file)
 /**
  * @file        main.cpp
  * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
  * @brief
  */
 #include <map>
 
 #include <poll.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include <askuser-notification/ask-user-client-channel.h>
 #include <askuser-notification/ask-user-server-channel.h>
+#include <askuser-notification/ask-user-types.h>
 
 std::map<int, int> m_sockets;
 
@@ -32,13 +35,14 @@ std::map<int, int> m_sockets;
 
 using namespace AskUser::Protocol;
 
-struct Callbacks : public IServerCallbacks {
-    Callbacks() : m_channel(nullptr) {}
+struct ServerCallbacks : public IServerCallbacks {
+    ServerCallbacks() : m_channel(nullptr) {}
 
     virtual void newConnection(ConnectionFd fd, const Credentials &creds) {
-        (void)fd;
-        (void)creds;
+        printf("call newConnection fd: %d credentials = { label: %s uid: %d }\n", fd,
+                creds.label.c_str(), creds.uid);
     }
+
     virtual void updateConnection(ConnectionFd fd, int mask) {
         printf("call updateFd %d %d\n", fd, mask);
         if (mask == 0) {
@@ -51,21 +55,21 @@ struct Callbacks : public IServerCallbacks {
     virtual void popup(ConnectionFd fd, RequestId id, Privilege &&priv) {
         printf("call popup %s \n", priv.c_str());
         if (m_channel)
-            m_channel->popupResponse(fd, id, 0xdeadbeef);
+            m_channel->popupResponse(fd, id, rand() % (ASKUSER_ALLOW_FOREVER + 1));
     }
 
-    void setChannel(IChannel *ptr) {
+    void setChannel(ServerChannel *ptr) {
         m_channel = ptr;
     }
 
 private:
-    IChannel *m_channel;
+    ServerChannel *m_channel;
 };
 
 void server(void) {
-    Callbacks *c = new Callbacks;
-    ChannelPtr ptr = createChannel(ServerCallbacksPtr(c));
-    c->setChannel(ptr.get());
+    ServerCallbacks *c = new ServerCallbacks;
+    ServerChannel *chan = new ServerChannel(ServerCallbacksPtr(c));
+    c->setChannel(chan);
 
     pollfd fd[100];
 
@@ -81,26 +85,93 @@ void server(void) {
             printf("Error in poll. Quit\n");
             return;
         }
-        for (int i=0; i<last; ++i) {
-            if (fd[i].revents & POLLIN)
-                ptr->process(fd[i].fd, FdMask::READ);
-            if (fd[i].revents & POLLOUT)
-                ptr->process(fd[i].fd, FdMask::WRITE);
+        for (int i = 0; i < last; ++i) {
+            if ((fd[i].revents & POLLIN) || (fd[i].revents & POLLOUT)) {
+                int mask = ((fd[i].revents & POLLIN) ? FdMask::READ : 0) |
+                           ((fd[i].revents & POLLOUT) ? FdMask::WRITE : 0);
+                chan->process(fd[i].fd, mask);
+            }
         }
     }
 }
 
-void stream() {
-    PrivilegeVector vect = {"http://tizen.org/privilege/camera", "http://tizen.org/privilege/contacts"};
-    int result;
-    UNUSED int ret = popup_launch("org.tizen.memo", "org.tizen.memo", getuid(), vect, result);
-    printf("Sended stream. Result: %x\n", result);
-}
+struct ClientCallbacks : public IClientCallbacks {
+    ClientCallbacks() : m_channel(nullptr) {}
+
+    virtual void updateConnection(ConnectionFd fd, int mask) {
+        printf("call updateFd %d %d\n", fd, mask);
+        if (mask == 0) {
+            // remove socket
+            m_sockets.erase(fd);
+            return;
+        }
+        m_sockets[fd] = mask;
+    }
+
+    virtual void popupResponse(RequestId id, int response) {
+        printf("response from popup id: %d response: %d\n", id, response);
+    }
+
+    void setChannel(ClientChannel *ptr) {
+        m_channel = ptr;
+    }
+
+private:
+    ClientChannel *m_channel;
+};
+
+void client() {
+    ClientCallbacks *c = new ClientCallbacks;
+    ClientChannel *chan = new ClientChannel(ClientCallbacksPtr(c));
+    c->setChannel(chan);
 
+    char privilege[4096];
+    pollfd fd[100];
+
+    while(1) {
+        int last = 0;
+        for (auto &e : m_sockets) {
+            fd[last].fd = e.first;
+            fd[last].revents = 0;
+            fd[last].events = ((e.second & FdMask::READ) ? POLLIN : 0) | ((e.second & FdMask::WRITE) ? POLLOUT : 0);
+            printf("poll fd = %d events = %d\n", e.first, fd[last].events);
+            last++;
+        }
+
+        // stdin
+        fd[last].fd = 0;
+        fd[last].revents = 0;
+        fd[last].events = POLLIN;
+        last++;
+
+        if (-1 == poll(fd, last, -1)) {
+            printf("Error in poll. Quit\n");
+            return;
+        }
+
+        for (int i = 0; i < last; ++i) {
+            switch (fd[i].fd) {
+            case 0:
+                if (fd[i].revents & POLLIN) {
+                    UNUSED int ret = scanf("%s", privilege);
+                    chan->popupRequest(privilege);
+                }
+                break;
+            default:
+                if ((fd[i].revents & POLLIN) || (fd[i].revents & POLLOUT)) {
+                    int mask = ((fd[i].revents & POLLIN) ? FdMask::READ : 0) |
+                               ((fd[i].revents & POLLOUT) ? FdMask::WRITE : 0);
+                    chan->process(fd[i].fd, mask);
+                }
+                break;
+            }
+        }
+    }
+}
 
 int main(){
     int com;
-    printf("0 - server, 1 - send popup, 2 - send toust1, 3 - send toust2\n>");
+    printf("0 - server, 1 - send popup\n>");
     UNUSED int ret = scanf("%d", &com);
 
     switch(com) {
@@ -108,7 +179,7 @@ int main(){
         server();
         break;
     case 1:
-        stream();
+        client();
         break;
     }
 
index 13edb9f..ffd95a0 100644 (file)
@@ -42,7 +42,7 @@ void Logic::addChannelFd(Protocol::ConnectionFd fd, const Protocol::Credentials
     auto it = m_connToInfo.find(fd);
     if (it != m_connToInfo.end()) {
         ALOGE("Connection with fd : " << fd << " already exists. Closing connection");
-        m_clientChannel->process(fd, 0);
+        m_serverChannel->process(fd, 0);
         return;
     }
 
@@ -115,7 +115,7 @@ Eina_Bool Logic::processChannel(int fd, int mask) {
             processEvents();
         }
         m_fdInfo.erase(fd);
-        m_clientChannel->process(fd, 0);
+        m_serverChannel->process(fd, 0);
         return ECORE_CALLBACK_CANCEL;
     }
     case FdChange::CHANGE:
@@ -149,16 +149,16 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
 
     if (policies.size() != 1) {
         ALOGE("Something strange happened, more than one policy for (" << it->second.appId << ", " << it->second.user << ", " << privilege << ") exists");
-        m_clientChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
+        m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
         return;
     }
 
     if (policies.front().getLevel() == "Allow") {
-        m_clientChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
+        m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
         return;
     }
     if (policies.front().getLevel() == "Deny") {
-        m_clientChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER);
+        m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER);
         return;
     }
 
@@ -222,13 +222,15 @@ Eina_Bool Logic::signalHandler(void *data, Ecore_Fd_Handler *) {
 }
 
 void Logic::prepareChannel() {
-    m_clientChannel = AskUser::Protocol::createChannel(
-            std::unique_ptr<AskUser::Protocol::IServerCallbacks>(new AskUser::Protocol::ServerCallbacks(this, &m_popupper)));
+    AskUser::Protocol::ServerCallbacksPtr callbacks(new AskUser::Protocol::ServerCallbacks(this, &m_popupper));
+    std::unique_ptr<AskUser::Protocol::ServerChannel> channel(new AskUser::Protocol::ServerChannel(std::move(callbacks)));
+
+    m_serverChannel = std::move(channel);
 }
 
 void Logic::updateChannel(int fd, int mask) {
     // TODO errors?
-    m_clientChannel->process(fd, mask);
+    m_serverChannel->process(fd, mask);
 }
 
 void Logic::init() {
@@ -290,7 +292,7 @@ void Logic::popupResponse(NResponseType response) {
     }
 
     // TODO create popup ids containing fd and request id
-    m_clientChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, clientResponse);
+    m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, clientResponse);
     finishCurrentEvent();
     processEvents();
 }
index 8c16a93..41712e5 100644 (file)
@@ -79,7 +79,7 @@ private:
     void finishCurrentEvent();
     void popupResponse(NResponseType response);
 
-    AskUser::Protocol::ChannelPtr m_clientChannel;
+    std::unique_ptr<AskUser::Protocol::ServerChannel> m_serverChannel;
     Popupper m_popupper;
 
     struct FdEvent {