Use ecore main loop only on popup service 90/108190/2
authorKyungwook Tak <k.tak@samsung.com>
Tue, 3 Jan 2017 09:10:49 +0000 (18:10 +0900)
committerkyungwook tak <k.tak@samsung.com>
Wed, 4 Jan 2017 03:41:13 +0000 (19:41 -0800)
refer https://review.tizen.org/gerrit/#/c/107312/
Need to loop intergation to ecore main loop.

Change-Id: I89903ded64cf8620adc576afcb52db8db837dac3
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
src/common/ui/popup-bin/CMakeLists.txt
src/common/ui/popup-bin/ecore-mainloop.cpp [new file with mode: 0644]
src/common/ui/popup-bin/ecore-mainloop.h [new file with mode: 0644]
src/common/ui/popup-bin/mainloop.h [new file with mode: 0644]
src/common/ui/popup-bin/popup.cpp
src/common/ui/popup-bin/tpkp_popup_logger.h [new file with mode: 0644]
src/common/ui/popup_runner.cpp

index 7f803decf15cca05a153d4c4ce4fa12a74e1175f..5ed2ad8ecd2f6e3b75da84250ac397a24d83fd8d 100644 (file)
@@ -32,6 +32,7 @@ INCLUDE_DIRECTORIES(
 
 SET(POPUP_SRCS
        popup.cpp
+       ecore-mainloop.cpp
        )
 
 ADD_EXECUTABLE(${TARGET_TPKP_POPUP} ${POPUP_SRCS})
diff --git a/src/common/ui/popup-bin/ecore-mainloop.cpp b/src/common/ui/popup-bin/ecore-mainloop.cpp
new file mode 100644 (file)
index 0000000..6251a6c
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include "ecore-mainloop.h"
+
+#include <utility>
+#include <exception>
+
+#include "tpkp_popup_logger.h"
+
+namespace Csr {
+
+Ecore_Fd_Handler_Flags EcoreMainloop::convertFlags(Mainloop::Event events)
+{
+       uint32_t flags = 0;
+
+       if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE)
+               flags |= ECORE_FD_READ;
+       if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE)
+               flags |= ECORE_FD_WRITE;
+
+       return static_cast<Ecore_Fd_Handler_Flags>(flags);
+}
+
+Mainloop::Event EcoreMainloop::convertFlags(Ecore_Fd_Handler *handler)
+{
+       Mainloop::Event flags = Mainloop::Event::NONE;
+
+       if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ))
+               flags |= Mainloop::Event::READ;
+       if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE))
+               flags |= Mainloop::Event::WRITE;
+       if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR))
+               flags |= Mainloop::Event::CLOSE;
+
+       return flags;
+}
+
+EcoreMainloop::EcoreMainloop() : m_isExitCalled(false), m_timer(nullptr) {}
+
+EcoreMainloop::~EcoreMainloop()
+{
+       if (this->m_timer)
+               ecore_timer_del(this->m_timer);
+
+       if (!this->m_isExitCalled)
+               elm_exit();
+}
+
+void EcoreMainloop::run(int timeout)
+{
+       this->dispatch(timeout);
+}
+
+void EcoreMainloop::dispatch(int timeout)
+{
+       if (timeout >= 0) {
+               this->m_timer = ecore_timer_add(
+                       static_cast<double>(timeout), &EcoreMainloop::ecoreTimeoutCb, this);
+
+               if (this->m_timer == nullptr) {
+                       SLOGE("Failed to ecore_timer_add()...");
+               }
+       }
+
+       elm_run();
+}
+
+void EcoreMainloop::addEventSource(
+       int fd, Mainloop::Event events, Mainloop::Callback &&callback)
+{
+       auto handler = ecore_main_fd_handler_add(
+               fd, convertFlags(events),
+               &EcoreMainloop::ecoreFdCallback, this, nullptr, nullptr);
+
+       if (handler == nullptr) {
+               SLOGE("failed to handle fd(%d) by ecore_main_fd_handler_add()", fd);
+               return;
+       }
+
+       std::unique_ptr<EventSource> source(new EventSource);
+       source->callback = std::move(callback);
+       source->handler = handler;
+
+       this->m_sources[fd] = std::move(source);
+}
+
+void EcoreMainloop::removeEventSource(int fd)
+{
+       auto it = this->m_sources.find(fd);
+
+       if (it == this->m_sources.end()) {
+               SLOGE("fd(%d) associated source is not found", fd);
+               return;
+       }
+
+       ecore_main_fd_handler_del(it->second->handler);
+
+       this->m_sources.erase(it);
+}
+
+Eina_Bool EcoreMainloop::ecoreFdCallback(void *data, Ecore_Fd_Handler *handler)
+{
+       auto mainloop = static_cast<EcoreMainloop *>(data);
+
+       if (mainloop == nullptr)
+               throw std::invalid_argument("userdata for ecore fd callback is invalid");
+
+       int fd = ecore_main_fd_handler_fd_get(handler);
+
+       auto it = mainloop->m_sources.find(fd);
+       if (it == mainloop->m_sources.end() || it->second == nullptr) {
+               SLOGE("no associated source found with fd: %d", fd);
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       it->second->callback(convertFlags(handler));
+
+       return ECORE_CALLBACK_RENEW;
+}
+
+Eina_Bool EcoreMainloop::ecoreTimeoutCb(void *data)
+{
+       auto mainloop = static_cast<EcoreMainloop *>(data);
+
+       if (mainloop == nullptr)
+               throw std::invalid_argument("userdata for ecore timeout callback is invalid");
+
+       if (mainloop->m_sources.size() == mainloop->m_domainSourceNum) {
+               SLOGI("There's no alive connection. Only listening socket opened. "
+                         "Let's exit the ecore main loop!");
+
+               elm_exit();
+
+               mainloop->m_timer = nullptr;
+               mainloop->m_isExitCalled = true;
+
+               return ECORE_CALLBACK_CANCEL;
+       } else {
+               SLOGI("Time out expired but there's alive connection "
+                         "so go ahead to next tick!");
+               return ECORE_CALLBACK_RENEW;
+       }
+}
+
+} // namespace Csr
diff --git a/src/common/ui/popup-bin/ecore-mainloop.h b/src/common/ui/popup-bin/ecore-mainloop.h
new file mode 100644 (file)
index 0000000..cf1b430
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <unordered_map>
+#include <memory>
+#include <Elementary.h>
+
+#include "mainloop.h"
+
+namespace Csr {
+
+class EcoreMainloop : public Mainloop {
+public:
+       EcoreMainloop();
+       virtual ~EcoreMainloop();
+
+       virtual void run(int timeout) override;
+
+       virtual void addEventSource(
+               int fd, Mainloop::Event event, Mainloop::Callback &&callback) override;
+       virtual void removeEventSource(int fd) override;
+
+private:
+       struct EventSource {
+               Mainloop::Callback callback;
+               Ecore_Fd_Handler *handler;
+       };
+
+       void dispatch(int timeout);
+
+       static Ecore_Fd_Handler_Flags convertFlags(Mainloop::Event events);
+       static Mainloop::Event convertFlags(Ecore_Fd_Handler *handler);
+
+       static Eina_Bool ecoreFdCallback(void *data, Ecore_Fd_Handler *handler);
+       static Eina_Bool ecoreTimeoutCb(void *data);
+
+       std::unordered_map<int, std::unique_ptr<EventSource>> m_sources;
+
+       bool m_isExitCalled;
+       Ecore_Timer *m_timer;
+};
+
+} // namespace Csr
diff --git a/src/common/ui/popup-bin/mainloop.h b/src/common/ui/popup-bin/mainloop.h
new file mode 100644 (file)
index 0000000..3fe5de0
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+namespace Csr {
+
+class Mainloop {
+public:
+       enum class Event : uint32_t {
+               NONE  = 0,
+               READ  = 1 << 0,
+               WRITE = 1 << 1,
+               CLOSE = 1 << 2
+       };
+
+       using Callback = std::function<void(Event event)>;
+
+       Mainloop() : m_domainSourceNum(0) {}
+       virtual ~Mainloop() {}
+
+       Mainloop(const Mainloop &) = delete;
+       Mainloop &operator=(const Mainloop &) = delete;
+       Mainloop(Mainloop &&) = delete;
+       Mainloop &operator=(Mainloop &&) = delete;
+
+       // timeout unit: seconds
+       // if timeout is negative value, no timeout on idle.
+       virtual void run(int timeout) = 0;
+
+       virtual void addEventSource(int fd, Event event, Callback &&callback) = 0;
+       virtual void removeEventSource(int fd) = 0;
+
+       void addDomainEventSource(int fd, Event event, Callback &&callback)
+       {
+               ++this->m_domainSourceNum;
+               this->addEventSource(fd, event, std::move(callback));
+       }
+
+protected:
+       size_t m_domainSourceNum;
+};
+
+template<typename T> using Underlying = typename std::underlying_type<T>::type;
+template<typename T>
+constexpr Underlying<T> underlying(T t) { return Underlying<T>(t); }
+
+inline constexpr Mainloop::Event operator&(Mainloop::Event e1, Mainloop::Event e2)
+{
+       return Mainloop::Event(underlying(e1) & underlying(e2));
+}
+
+inline Mainloop::Event &operator&=(Mainloop::Event &e1, Mainloop::Event e2)
+{
+       return e1 = e1 & e2;
+}
+
+inline constexpr Mainloop::Event operator|(Mainloop::Event e1, Mainloop::Event e2)
+{
+       return Mainloop::Event(underlying(e1) | underlying(e2));
+}
+
+inline Mainloop::Event &operator|=(Mainloop::Event &e1, Mainloop::Event e2)
+{
+       return e1 = e1 | e2;
+}
+
+inline constexpr Mainloop::Event operator~(Mainloop::Event e)
+{
+       return Mainloop::Event(~underlying(e));
+}
+
+} // namespace Csr
index 4b8ae15d0201979ba363c1e01b0213bc2a41fccf..18f8d2aeb3c3573bdd1f3e7ea93e03adbf3d295a 100644 (file)
  * @author      Janusz Kozerski (j.kozerski@samsung.com)
  * @version     1.0
  */
-#include <unistd.h>
 #include <vector>
 #include <memory>
 #include <string>
 #include <functional>
+#include <map>
+#include <unistd.h>
 #include <libintl.h>
-#include <poll.h>
 #include <sys/un.h>
 #include <time.h>
 
 #include <vconf.h>
 
 #include "tpkp_exception.h"
-#include "tpkp_logger.h"
+#include "tpkp_popup_logger.h"
+#include "ecore-mainloop.h"
 #include "ui/popup_common.h"
 
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "TPKP_POPUP"
-
 using namespace TPKP::UI;
 
 namespace {
@@ -52,20 +48,24 @@ struct TpkpPopup {
        /* inputs */
        std::string hostname;
        int timeout;
-
        /* internal data fields */
        Evas_Object *win;
 
        /* output */
        TPKP::UI::Response result;
 
-       TpkpPopup() :
+       int fd;
+
+       TpkpPopup(int fd) :
                hostname(),
                timeout(-1),
                win(nullptr),
-               result(TPKP::UI::Response::ERROR) {}
+               result(TPKP::UI::Response::ERROR),
+               fd(fd) {}
 };
 
+std::map<int, std::unique_ptr<TpkpPopup>> g_pdpMap;
+
 struct SockRaii {
        int sock;
        SockRaii() : sock(-1) {}
@@ -82,8 +82,6 @@ struct ElmRaii {
        {
                SLOGD("elm_init()");
                elm_init(argc, argv);
-
-               elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
        }
 
        virtual ~ElmRaii()
@@ -93,6 +91,23 @@ struct ElmRaii {
        }
 };
 
+void deserialize(TpkpPopup *pdp, BinaryStream &stream)
+{
+       Deserialization::Deserialize(stream, pdp->hostname);
+       Deserialization::Deserialize(stream, pdp->timeout);
+
+       SLOGD("Params from popup_runner: hostname[%s] timeout[%d]",
+               pdp->hostname.c_str(), pdp->timeout);
+}
+
+BinaryStream serialize(TpkpPopup *pdp)
+{
+       BinaryStream stream;
+       Serialization::Serialize(stream, static_cast<int>(pdp->result));
+
+       return stream;
+}
+
 void answerAllowCb(void *data, Evas_Object * /* obj */, void * /* event_info */)
 {
        SLOGD("allow answer");
@@ -125,6 +140,19 @@ void answerDenyCb(void *data, Evas_Object * /* obj */, void * /* event_info */)
        }
 }
 
+void onDone(void *data, Evas *, Evas_Object *, void *)
+{
+       TPKP_CHECK_THROW_EXCEPTION(data != nullptr,
+               TPKP_E_INVALID_PARAMETER, "data shouldn't be null on evas callbacks");
+
+       TpkpPopup *pdp = static_cast<TpkpPopup *>(data);
+
+       SLOGD("pdp->result : %d", static_cast<int>(pdp->result));
+
+       /* send result */
+       sendStream(pdp->fd, serialize(pdp));
+}
+
 Eina_Bool timeoutCb(void *data)
 {
        TPKP_CHECK_THROW_EXCEPTION(data != nullptr,
@@ -142,12 +170,12 @@ Eina_Bool timeoutCb(void *data)
        return ECORE_CALLBACK_CANCEL;
 }
 
-CstringPtr getPopupContentString(TpkpPopup *pdp)
+CstringPtr getPopupContentString(const std::string &hostname)
 {
        char *contentFormat = dgettext(PROJECT_NAME, "SID_CONTENT_PUBLIC_KEY_MISMATCHED");
        char *content = nullptr;
 
-       if (asprintf(&content, contentFormat, pdp->hostname.c_str()) == -1)
+       if (asprintf(&content, contentFormat, hostname.c_str()) == -1)
                TPKP_THROW_EXCEPTION(TPKP_E_MEMORY,
                        "Failed to alloc memory for popup text");
 
@@ -189,7 +217,7 @@ void showPopup(TpkpPopup *pdp)
        evas_object_show(win);
 
        /* create popup */
-       auto contentString = getPopupContentString(pdp);
+       auto contentString = getPopupContentString(pdp->hostname);
        Evas_Object *popup = elm_popup_add(win);
        evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        elm_object_text_set(popup, contentString.get());
@@ -214,37 +242,11 @@ void showPopup(TpkpPopup *pdp)
        evas_object_show(buttonDeny);
 
        if (pdp->timeout > 0)
-               ecore_timer_add(pdp->timeout / 1000, timeoutCb, pdp);
+               ecore_timer_add(static_cast<double>(pdp->timeout) / 1000, timeoutCb, pdp);
 
        pdp->win = win;
 
-       SLOGD("elm_run start");
-       elm_run();
-}
-
-/*
- *  child receive list
- *  - std::string hostname
- */
-void deserialize(TpkpPopup *pdp, BinaryStream &stream)
-{
-       Deserialization::Deserialize(stream, pdp->hostname);
-       Deserialization::Deserialize(stream, pdp->timeout);
-
-       SLOGD("Params from popup_runner: hostname[%s] timeout[%d]",
-               pdp->hostname.c_str(), pdp->timeout);
-}
-
-/*
- *  child send list
- *  - TPKP::UI::Response response (int)
- */
-BinaryStream serialize(TpkpPopup *pdp)
-{
-       BinaryStream stream;
-       Serialization::Serialize(stream, static_cast<int>(pdp->result));
-
-       return stream;
+       evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, onDone, pdp);
 }
 
 int getSockFromSystemd(void)
@@ -260,6 +262,52 @@ int getSockFromSystemd(void)
        TPKP_THROW_EXCEPTION(TPKP_E_IO, "Failed to get sock from systemd.");
 }
 
+void onClose(int fd, Csr::Mainloop *loop)
+{
+       close(fd);
+
+       loop->removeEventSource(fd);
+       g_pdpMap.erase(fd);
+}
+
+void onRequest(int fd)
+{
+       auto it = g_pdpMap.find(fd);
+       if (it == g_pdpMap.end())
+               it = g_pdpMap.insert(std::make_pair(
+                       fd, std::unique_ptr<TpkpPopup>(new TpkpPopup(fd)))).first;
+
+       /* receive arguments */
+       auto stream = receiveStream(fd);
+       deserialize(it->second.get(), stream);
+
+       showPopup(it->second.get());
+}
+
+void onAccept(int domainSockFd, Csr::Mainloop *loop)
+{
+       struct sockaddr_un client;
+       memset(&client, 0, sizeof(struct sockaddr));
+       socklen_t len = sizeof(client);
+
+       int fd = accept(domainSockFd, reinterpret_cast<struct sockaddr *>(&client), &len);
+       TPKP_CHECK_THROW_EXCEPTION(fd >= 0, TPKP_E_IO, "error in accept().");
+
+       SLOGD("client accepted with fd: %d", fd);
+
+       loop->addEventSource(fd,
+               Csr::Mainloop::Event::READ | Csr::Mainloop::Event::CLOSE,
+               [&, fd, loop](Csr::Mainloop::Event events) {
+                       if ((events & Csr::Mainloop::Event::CLOSE) != Csr::Mainloop::Event::NONE) {
+                               onClose(fd, loop);
+                               return;
+                       }
+
+                       onRequest(fd);
+               }
+       );
+}
+
 } // namespace anonymous
 
 int main(int argc, char **argv)
@@ -272,52 +320,23 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, vconf_get_str(VCONFKEY_LANGSET));
 
        try {
-               struct sockaddr_un clientaddr;
-               int client_len = sizeof(clientaddr);
-
-               struct pollfd fds[1];
-               fds[0].fd = getSockFromSystemd();
-               fds[0].events = POLLIN;
-
-               SLOGD("server fd from systemd: %d", fds[0].fd);
-
-               while (true) {
-                       /* non blocking poll */
-                       int ret = poll(fds, 1, 0);
-                       if (ret < 0) {
-                               TPKP_THROW_EXCEPTION(TPKP_E_IO, "poll() error. errno: " << errno);
-                       } else if (ret == 0) {
-                               SLOGD("tpkp-popup backend service timeout. Let's be deactivated");
-                               return 0;
-                       }
-
-                       /* ready to accept! */
-
-                       memset(&clientaddr, 0, client_len);
+               std::unique_ptr<Csr::Mainloop> loop(new Csr::EcoreMainloop);
 
-                       int clientFd = accept(fds[0].fd, (struct sockaddr *)&clientaddr, (socklen_t *)&client_len);
-                       TPKP_CHECK_THROW_EXCEPTION(clientFd >= 0, TPKP_E_IO, "Error in func accept()");
-                       SLOGD("client accepted with fd: %d", clientFd);
+               SockRaii domainSock(getSockFromSystemd());
 
-                       SockRaii clientSock(clientFd);
+               loop->addDomainEventSource(
+                       domainSock.sock, Csr::Mainloop::Event::READ | Csr::Mainloop::Event::CLOSE,
+                       [&](Csr::Mainloop::Event events) {
+                               if ((events & Csr::Mainloop::Event::READ) == Csr::Mainloop::Event::NONE)
+                                       return;
 
-                       TpkpPopup pd;
-                       TpkpPopup *pdp = &pd;
-
-                       /* receive arguments */
-                       BinaryStream stream = receiveStream(clientFd);
-                       deserialize(pdp, stream);
-
-                       /* get user response */
-                       showPopup(pdp);
-                       SLOGD("pdp->result : %d", static_cast<int>(pdp->result));
+                               onAccept(domainSock.sock, loop.get());
+                       }
+               );
 
-                       /* send result */
-                       stream = serialize(pdp);
-                       sendStream(clientFd, stream);
+               loop->run(10);
 
-                       SLOGD("tpkp-popup done successfully!");
-               }
+               SLOGI("turned off by timeout...");
        } catch (const TPKP::Exception &e) {
                SLOGE("Exception[%d]: %s", e.code(), e.what());
        } catch (const std::bad_alloc &e) {
diff --git a/src/common/ui/popup-bin/tpkp_popup_logger.h b/src/common/ui/popup-bin/tpkp_popup_logger.h
new file mode 100644 (file)
index 0000000..b18de5e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 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        tpkp_popup_logger.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       Tizen Https Public Key Pinning dlog wrapper for popup service.
+ */
+#pragma once
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "TPKP_POPUP"
+
+#include <dlog.h>
index 0aa9fe196df63c31c4863af75bd632f2ffb19746..4ada3bdfe1f4147d0030e5e2e230c9e7798ca0a6 100644 (file)
@@ -70,6 +70,11 @@ Response runPopup(const std::string &hostname, int timeout) noexcept
        try {
                SLOGD("hostname: %s", hostname.c_str());
 
+               if (timeout <= 0)
+                       timeout = -1;
+               else if (timeout < TIMEOUT_MS_MIN)
+                       timeout = TIMEOUT_MS_MIN;
+
                TpkpPopupParent pd;
                TpkpPopupParent *pdp = &pd;
 
@@ -78,12 +83,10 @@ Response runPopup(const std::string &hostname, int timeout) noexcept
 
                BinaryStream inStream = serialize(pdp);
 
-               if (timeout <= 0)
-                       timeout = -1;
-               else if (timeout < TIMEOUT_MS_MIN)
-                       timeout = TIMEOUT_MS_MIN;
-
-               ServiceConnection connection(SOCK_PATH, timeout);
+               // popup timeout is managed by popup service side also so
+               // have some(1 second) spare to give change to popup service to timed out.
+               ServiceConnection connection(SOCK_PATH,
+                       (timeout > 0) ? (timeout + 1000) : timeout);
                BinaryStream outStream = connection.processRequest(inStream);
 
                deserialize(pdp, outStream);