Implement the agent daemon 56/141256/13
authorMu-Woong Lee <muwoong.lee@samsung.com>
Sat, 29 Jul 2017 09:59:44 +0000 (18:59 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Tue, 1 Aug 2017 09:43:42 +0000 (18:43 +0900)
Change-Id: I7542bd9f11f899574d910d9d2adbab76e6fb18dd
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
18 files changed:
CMakeLists.txt
packaging/context-service.spec
packaging/contextd-agent.service
packaging/contextd-agent.socket [new file with mode: 0644]
src/agent/AgentDBus.cpp [new file with mode: 0644]
src/agent/AgentDBus.h [new file with mode: 0644]
src/agent/AgentMain.cpp
src/agent/AgentSocket.cpp [new file with mode: 0644]
src/agent/AgentSocket.h [new file with mode: 0644]
src/agent/AgentUtil.cpp [new file with mode: 0644]
src/agent/AgentUtil.h [new file with mode: 0644]
src/agent/CMakeLists.txt
src/agent/PluginLoader.cpp [new file with mode: 0644]
src/agent/PluginLoader.h [new file with mode: 0644]
src/server/CMakeLists.txt
src/server/ServerMain.cpp
src/shared/ServerBase.cpp [new file with mode: 0644]
src/shared/ServerBase.h [new file with mode: 0644]

index c9d1849..549a8e0 100644 (file)
@@ -2,7 +2,12 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 PROJECT(context-service)
 INCLUDE(GNUInstallDirs)
 
+INCLUDE_DIRECTORIES(
+       ${CMAKE_SOURCE_DIR}/src/shared
+)
+
 ADD_DEFINITIONS(-O2 -Wall -fPIC -fPIE -fdata-sections -ffunction-sections -fvisibility=hidden)
+ADD_DEFINITIONS(-D_LIBDIR_="${LIBDIR}")
 ADD_DEFINITIONS(-fdiagnostics-color)
 SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIC -pie -Wl,--as-needed -Wl,--gc-sections -Wl,--print-gc-sections")
 SET(CMAKE_VERBOSE_MAKEFILE OFF)
index 130e273..ca3b359 100644 (file)
@@ -8,8 +8,10 @@ Source0:    %{name}-%{version}.tar.gz
 Source1:       contextd.service
 Source2:       org.tizen.context.conf
 Source3:       contextd-agent.service
+Source4:       contextd-agent.socket
 
 BuildRequires: cmake
+BuildRequires: pkgconfig(libsystemd-daemon)
 BuildRequires: pkgconfig(libsystemd-login)
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-2.0)
@@ -49,7 +51,7 @@ export CXXFLAGS+=" -Wformat=2 -Wno-empty-body -fomit-frame-pointer -fno-optimize
 export CXXFLAGS+=" -fno-strict-aliasing -fno-unroll-loops -fsigned-char -fstrict-overflow"
 export CXXFLAGS+=" -Wnon-virtual-dtor -std=c++0x"
 
-%cmake .
+%cmake . -DLIBDIR=%{_libdir}
 make %{?_smp_mflags}
 
 %install
@@ -62,8 +64,10 @@ ln -s ../contextd.service %{buildroot}%{_unitdir}/multi-user.target.wants/contex
 mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d
 install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/dbus-1/system.d/
 
-mkdir -p %{buildroot}%{_unitdir_user}
+mkdir -p %{buildroot}%{_unitdir_user}/sockets.target.wants
 install -m 0644 %{SOURCE3} %{buildroot}%{_unitdir_user}
+install -m 0644 %{SOURCE4} %{buildroot}%{_unitdir_user}
+ln -s ../contextd-agent.socket %{buildroot}%{_unitdir_user}/sockets.target.wants/contextd-agent.socket
 
 %files
 %manifest packaging/%{name}.manifest
@@ -77,4 +81,6 @@ install -m 0644 %{SOURCE3} %{buildroot}%{_unitdir_user}
 %manifest packaging/%{name}.manifest
 %{_bindir}/contextd-agent
 %{_unitdir_user}/contextd-agent.service
+%{_unitdir_user}/contextd-agent.socket
+%{_unitdir_user}/*/contextd-agent.socket
 %license LICENSE
index 8eb83c4..4e6819c 100644 (file)
@@ -2,5 +2,10 @@
 Description=Contextual Service Framework User-Level Agent Daemon
 
 [Service]
-Type=simple
+Type=notify
 ExecStart=/usr/bin/contextd-agent
+Sockets=contextd-agent.socket
+Restart=no
+
+[Install]
+WantedBy=sockets.target
diff --git a/packaging/contextd-agent.socket b/packaging/contextd-agent.socket
new file mode 100644 (file)
index 0000000..71de9ef
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Context-Agent Socket
+
+[Socket]
+ListenStream=/run/user_ext/%U/.contextd-agent.socket
+Service=contextd-agent.service
+Accept=false
diff --git a/src/agent/AgentDBus.cpp b/src/agent/AgentDBus.cpp
new file mode 100644 (file)
index 0000000..fa952b0
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdexcept>
+#include "AgentDBus.h"
+
+using namespace ctx;
+
+AgentDBus::AgentDBus() :
+       __connection(NULL)
+{
+       if (!__init())
+               throw std::runtime_error("DBus connection failed");
+
+       _I("Connection established (%s)", g_dbus_connection_get_unique_name(__connection));
+}
+
+AgentDBus::~AgentDBus()
+{
+       __release();
+}
+
+GDBusConnection* AgentDBus::getConnection()
+{
+       return __connection;
+}
+
+bool AgentDBus::__init()
+{
+       GError *gerr = NULL;
+       gchar *addr = NULL;
+
+       addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, NULL, &gerr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_RETURN_TAG(addr, false, _E, "Getting address failed");
+
+       __connection = g_dbus_connection_new_for_address_sync(addr,
+                       (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
+                       NULL, NULL, &gerr);
+       g_free(addr);
+       HANDLE_GERROR(gerr);
+       IF_FAIL_RETURN_TAG(__connection, false, _E, "Connection failed");
+
+       return true;
+}
+
+void AgentDBus::__release()
+{
+       if (__connection) {
+               g_dbus_connection_flush_sync(__connection, NULL, NULL);
+               g_dbus_connection_close_sync(__connection, NULL, NULL);
+               g_object_unref(__connection);
+       }
+
+       _I("Connection released");
+}
diff --git a/src/agent/AgentDBus.h b/src/agent/AgentDBus.h
new file mode 100644 (file)
index 0000000..345cb3e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_AGENT_DBUS_H__
+#define __CONTEXT_AGENT_DBUS_H__
+
+#include <ContextTypes.h>
+
+namespace ctx {
+
+       class AgentDBus {
+       public:
+               AgentDBus();
+               ~AgentDBus();
+
+               GDBusConnection* getConnection();
+
+       private:
+               bool __init();
+               void __release();
+
+               GDBusConnection* __connection;
+       };
+
+}
+
+#endif
index fc1dc8d..fd271be 100644 (file)
  * limitations under the License.
  */
 
+#include <csignal>
 #include <cstdlib>
+#include <systemd/sd-daemon.h>
 
-int main(int argc, char* argv[])
+#include <ServerBase.h>
+#include "AgentDBus.h"
+#include "AgentUtil.h"
+#include "PluginLoader.h"
+#include "AgentSocket.h"
+
+using namespace ctx;
+
+static MainLoop __mainLoop;
+
+static void __on_signal(int signum)
+{
+       _I(YELLOW("SIGNAL-%d: '%s'"), signum, strsignal(signum));
+       __mainLoop.stop();
+}
+
+int main(int argc, char **argv)
 {
+       std::signal(SIGINT, __on_signal);
+       std::signal(SIGHUP, __on_signal);
+       std::signal(SIGTERM, __on_signal);
+       std::signal(SIGQUIT, __on_signal);
+
+       AgentDBus agentDBus;
+       AgentUtil agentUtil(agentDBus);
+       PluginLoader pluginLoader(agentUtil);
+       AgentSocket agentSocket(pluginLoader);
+
+       sd_notify(0, "READY=1");
+
+       __mainLoop.start();
+
+       sd_notify(0, "STOPPING=1");
+
        return EXIT_SUCCESS;
 }
diff --git a/src/agent/AgentSocket.cpp b/src/agent/AgentSocket.cpp
new file mode 100644 (file)
index 0000000..e8d45b9
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <systemd/sd-daemon.h>
+#include <stdexcept>
+#include <IAgentPlugin.h>
+#include "PluginLoader.h"
+#include "AgentSocket.h"
+
+#define PATH_LENGTH            48
+#define TERM_MSG_ID            0xFFFF
+
+using namespace ctx;
+
+struct CommandInfo {
+       PluginLoader* pluginLoader;
+       uint16_t id;
+       uint8_t length;
+       void* command;
+
+       CommandInfo(PluginLoader* loader, uint16_t i, uint8_t len, char* cmd) :
+               pluginLoader(loader), id(i), length(len), command(NULL)
+       {
+               command = malloc(length);
+
+               if (!command)
+                       throw std::bad_alloc();
+
+               memcpy(command, cmd, length);
+       }
+
+       ~CommandInfo()
+       {
+               free(command);
+       }
+};
+
+static gboolean __send_command(gpointer data)
+{
+       CommandInfo* info = static_cast<CommandInfo*>(data);
+
+       info->pluginLoader->send(info->id, info->length, info->command);
+
+       delete info;
+
+       return G_SOURCE_REMOVE;
+}
+
+static bool __set_close_on_exec(int fd)
+{
+       if (::fcntl(fd, F_SETFL, FD_CLOEXEC) == -1)
+               return false;
+
+       return true;
+}
+
+static int __get_socket_fd(const char* path)
+{
+       int n = sd_listen_fds(0);
+       IF_FAIL_RETURN_TAG(n > 0, E_ACCESS, _E, "sd_listen_fds() failed");
+
+       for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
+               if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path, 0) > 0) {
+                       __set_close_on_exec(fd);
+                       return fd;
+               }
+       }
+
+       return E_ACCESS;
+}
+
+AgentSocket::AgentSocket(PluginLoader& loader) :
+       __sockFd(-1),
+       __listening(false),
+       __listeningThread(NULL),
+       __pluginLoader(loader)
+{
+       if (!__init()) {
+               __release();
+               throw std::runtime_error("Socket connection failed");
+       }
+
+       _I("Listening...");
+}
+
+AgentSocket::~AgentSocket()
+{
+       __release();
+}
+
+bool AgentSocket::__init()
+{
+       char path[PATH_LENGTH];
+       g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
+
+       _D("Socket Path: %s", path);
+
+       __sockFd = __get_socket_fd(path);
+       IF_FAIL_RETURN_TAG(__sockFd > 0, false, _E, "Failed to get the socket fd");
+
+       __listening.store(true);
+       __listeningThread = g_thread_new(NULL, __listen, this);
+       IF_FAIL_RETURN_TAG(__listeningThread, false, _E, "Thread creation failed");
+
+       return true;
+}
+
+gpointer AgentSocket::__listen(gpointer data)
+{
+       static_cast<AgentSocket*>(data)->__listen();
+       return NULL;
+}
+
+void AgentSocket::__listen()
+{
+       int msgsock = 0;
+
+       while (__listening.load()) {
+               msgsock = accept(__sockFd, 0, 0);
+
+               if (msgsock < 0) {
+                       _D("accept() failed");
+                       continue;
+               }
+
+               if (!__readCommand(msgsock)) {
+                       close(msgsock);
+                       break;
+               }
+
+               close(msgsock);
+       }
+}
+
+bool AgentSocket::__readCommand(int msgsock)
+{
+       uint16_t id = 0;
+       uint8_t length = 0;
+       int rval = 0;
+       char buf[CTX_AGENT_COMMAND_LIMIT] = {0};
+
+       rval = read(msgsock, &id, sizeof(id));
+       IF_FAIL_RETURN_TAG(rval == sizeof(id), false, _E, "read() failed");
+
+       if (id == TERM_MSG_ID) {
+               _D("Stop listening...");
+               return false;
+       }
+
+       rval = read(msgsock, &length, sizeof(length));
+       IF_FAIL_RETURN_TAG(rval == sizeof(length), false, _E, "read() failed");
+
+       rval = read(msgsock, buf, length);
+       IF_FAIL_RETURN_TAG(rval == static_cast<int>(length), false, _E, "read() failed");
+
+
+       buf[length] = '\0';
+
+       CommandInfo* info = new CommandInfo(&__pluginLoader, id, length, buf);
+       g_idle_add(__send_command, info);
+
+       return true;
+}
+
+void AgentSocket::__release()
+{
+       if (!__listening.load())
+               return;
+
+       __listening.store(false);
+       __terminate();
+
+       if (__listeningThread)
+               g_thread_join(__listeningThread);
+
+       close(__sockFd);
+}
+
+bool AgentSocket::__terminate()
+{
+       int sock = -1;
+       sockaddr_un addr;
+       char path[PATH_LENGTH];
+       const uint16_t termMsg = TERM_MSG_ID;
+
+       g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
+       IF_FAIL_RETURN_TAG(strlen(path) < sizeof(addr.sun_path), false, _E, "Invalid path");
+
+       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       IF_FAIL_RETURN_TAG(sock > 0, false, _E, "socket creation failed");
+
+       bzero(&addr, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+       addr.sun_path[sizeof(path)] = '\0';
+
+       if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
+               close(sock);
+               _E("Connection failed");
+               return false;
+       }
+
+       if (write(sock, &termMsg, sizeof(termMsg)) < 0) {
+               close(sock);
+               _E("Sending failed");
+               return false;
+       }
+
+       close(sock);
+       return true;
+}
diff --git a/src/agent/AgentSocket.h b/src/agent/AgentSocket.h
new file mode 100644 (file)
index 0000000..d3f1ebd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_AGENT_SOCKET_H__
+#define __CONTEXT_AGENT_SOCKET_H__
+
+#include <atomic>
+#include <ContextTypes.h>
+
+namespace ctx {
+
+       class PluginLoader;
+
+       class AgentSocket {
+       public:
+               AgentSocket(PluginLoader& loader);
+               ~AgentSocket();
+
+       private:
+               bool __init();
+               void __release();
+
+               void __listen();
+               bool __readCommand(int msgsock);
+               bool __terminate();
+
+               static gpointer __listen(gpointer data);
+
+               int __sockFd;
+               std::atomic_bool __listening;
+               GThread* __listeningThread;
+               PluginLoader& __pluginLoader;
+       };
+
+}
+
+#endif
diff --git a/src/agent/AgentUtil.cpp b/src/agent/AgentUtil.cpp
new file mode 100644 (file)
index 0000000..a7bdee7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 "AgentDBus.h"
+#include "AgentUtil.h"
+
+using namespace ctx;
+
+AgentUtil::AgentUtil(AgentDBus& agentDBus) :
+       __agentDBus(agentDBus)
+{
+}
+
+AgentUtil::~AgentUtil()
+{
+}
+
+GDBusConnection* AgentUtil::getDBusConnection()
+{
+       return __agentDBus.getConnection();
+}
diff --git a/src/agent/AgentUtil.h b/src/agent/AgentUtil.h
new file mode 100644 (file)
index 0000000..008162f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_AGENT_UTIL_H__
+#define __CONTEXT_AGENT_UTIL_H__
+
+#include <ContextTypes.h>
+#include <IAgentPlugin.h>
+
+namespace ctx {
+
+       class AgentDBus;
+
+       class AgentUtil : public IAgentUtil {
+       public:
+               AgentUtil(AgentDBus& agentDBus);
+               ~AgentUtil();
+
+               GDBusConnection* getDBusConnection();
+
+       private:
+               AgentDBus& __agentDBus;
+       };
+
+}
+
+#endif
index 69d426e..cbe2063 100644 (file)
@@ -2,9 +2,15 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
 SET(target "contextd-agent")
 
-SET(DEPS glib-2.0 gio-2.0 gmodule-2.0 dlog capi-base-common)
+SET(DEPS glib-2.0 gio-2.0 gmodule-2.0 libsystemd-daemon dlog capi-base-common)
 
-FILE(GLOB_RECURSE SRCS *.cpp)
+SET(INCDIR "${CMAKE_INSTALL_INCLUDEDIR}/context-service")
+
+INCLUDE_DIRECTORIES(
+       ${CMAKE_INSTALL_PREFIX}/${INCDIR}/private
+)
+
+FILE(GLOB SRCS *.cpp ../shared/*.cpp)
 MESSAGE("Sources: ${SRCS}")
 
 INCLUDE(FindPkgConfig)
diff --git a/src/agent/PluginLoader.cpp b/src/agent/PluginLoader.cpp
new file mode 100644 (file)
index 0000000..c49b617
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdexcept>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <gmodule.h>
+#include "AgentUtil.h"
+#include "PluginLoader.h"
+
+#define PLUGIN_DIR     _LIBDIR_ "/" CTX_AGENT_PLUGIN_DIR
+
+using namespace ctx;
+
+PluginLoader::PluginLoader(AgentUtil& agentUtil) :
+       __agentUtil(agentUtil)
+{
+       if (!__load()) {
+               __unload();
+               throw std::runtime_error("Plugin loading failed");
+       }
+
+       _I("%u plugins loaded", __plugins.size());
+}
+
+PluginLoader::~PluginLoader()
+{
+       __unload();
+}
+
+void PluginLoader::send(uint16_t id, uint8_t length, const void* command)
+{
+       for (auto& agent : __plugins) {
+               if (agent->getId() == id) {
+                       agent->doAction(length, command);
+                       return;
+               }
+       }
+
+       _W("Agent not found");
+}
+
+bool PluginLoader::__load()
+{
+       DIR* dir = NULL;
+       struct dirent* entry = NULL;
+       struct stat fileStat;
+
+       _D("Scanning %s", PLUGIN_DIR);
+
+       dir = opendir(PLUGIN_DIR);
+       IF_FAIL_RETURN_TAG(dir, false, _E, "Failed to open: %s", PLUGIN_DIR);
+
+       while ((entry = readdir(dir))) {
+               std::string filePath(PLUGIN_DIR "/");
+               filePath.append(entry->d_name);
+
+               if (lstat(filePath.c_str(), &fileStat) != 0)
+                       continue;
+
+               if (!S_ISREG(fileStat.st_mode))
+                       continue;
+
+               if (!__load(filePath)) {
+                       closedir(dir);
+                       _E("Failed to load %s", filePath.c_str());
+                       return false;
+               }
+       }
+
+       closedir(dir);
+       return true;
+}
+
+bool PluginLoader::__load(const std::string& filePath)
+{
+       _D("Loading plugins from %s", filePath.c_str());
+
+       GModule *soHandle = g_module_open(filePath.c_str(), G_MODULE_BIND_LAZY);
+       IF_FAIL_RETURN_TAG(soHandle, false, _E, "%s", g_module_error());
+
+       create_plugins_t createPlugins;
+       if (!g_module_symbol(soHandle, CTX_AGENT_CREATE_FUNC_SYM, (gpointer*)&createPlugins) || !createPlugins) {
+               _E("%s", g_module_error());
+               g_module_close(soHandle);
+               return false;
+       }
+
+       IAgentPlugin** plugins = createPlugins(&__agentUtil);
+       for (int i = 0; plugins[i] != NULL; ++i) {
+               __plugins.push_back(plugins[i]);
+       }
+
+       return true;
+}
+
+void PluginLoader::__unload()
+{
+       for (auto& plugin : __plugins) {
+               delete plugin;
+       }
+
+       __plugins.clear();
+}
diff --git a/src/agent/PluginLoader.h b/src/agent/PluginLoader.h
new file mode 100644 (file)
index 0000000..557c22a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_AGENT_PLUGIN_LOADER_H__
+#define __CONTEXT_AGENT_PLUGIN_LOADER_H__
+
+#include <string>
+#include <vector>
+#include <ContextTypes.h>
+#include <IAgentPlugin.h>
+
+namespace ctx {
+
+       class AgentUtil;
+
+       class PluginLoader {
+       public:
+               PluginLoader(AgentUtil& agentUtil);
+               ~PluginLoader();
+
+               void send(uint16_t id, uint8_t length, const void* command);
+
+       private:
+               bool __load();
+               bool __load(const std::string& filePath);
+               void __unload();
+
+               AgentUtil& __agentUtil;
+               std::vector<IAgentPlugin*> __plugins;
+       };
+
+}
+
+#endif
index b0c8ba2..0ec7782 100644 (file)
@@ -26,7 +26,7 @@ INCLUDE_DIRECTORIES(
        ${CMAKE_INSTALL_PREFIX}/${INCDIR}/private
 )
 
-FILE(GLOB_RECURSE SRCS *.cpp)
+FILE(GLOB SRCS *.cpp ../shared/*.cpp)
 MESSAGE("Sources: ${SRCS}")
 
 INCLUDE(FindPkgConfig)
index 312574d..ae62b7c 100644 (file)
 #include <csignal>
 #include <cstdlib>
 #include <cstring>
-#include <new>
-#include <exception>
-#include <stdexcept>
 
 #include <ContextTypes.h>
 #include <ServerUtil.h>
+#include <ServerBase.h>
 #include "DBusConnector.h"
 #include "ServiceLoader.h"
 #include "ActiveUserMonitor.h"
 #include "AlarmInitializer.h"
 
-#define NEW_FAIL_LIMIT 3
-
 using namespace ctx;
 
-namespace {
-       class MainLoop {
-       public:
-               static bool start();
-               static void stop();
-       private:
-               MainLoop() {}
-               static GMainLoop* __mainLoop;
-       };
-}
-
-GMainLoop* MainLoop::__mainLoop = NULL;
-
-bool MainLoop::start()
-{
-       __mainLoop = g_main_loop_new(NULL, FALSE);
-       IF_FAIL_RETURN_TAG(__mainLoop, false, _E, E_STR_ALLOC);
-
-       _I(CYAN("Starting..."));
-       g_main_loop_run(__mainLoop);
-
-       g_main_loop_unref(__mainLoop);
-
-       return true;
-}
-
-void MainLoop::stop()
-{
-       _I(PURPLE("Terminating..."));
-       g_main_loop_quit(__mainLoop);
-}
-
+static MainLoop __mainLoop;
 static ServiceLoader __serviceLoader;
 static ActiveUserMonitor __activeUserMonitor(&__serviceLoader);
 static AlarmInitializer __alarmInit;
@@ -89,7 +54,7 @@ static gboolean __stop_service(gpointer data)
        _I("Unloading services");
        __serviceLoader.stopAll();
 
-       MainLoop::stop();
+       __mainLoop.stop();
        return G_SOURCE_REMOVE;
 }
 
@@ -114,43 +79,16 @@ static void __on_signal(int signum)
        }
 }
 
-static void __on_terminate()
-{
-       try {
-               auto unknown = std::current_exception();
-               if (unknown) {
-                       std::rethrow_exception(unknown);
-               }
-       } catch (const std::exception& e) {
-               _E(RED("Unexpected exception: %s"), e.what());
-       } catch (...) {
-               _E(RED("Unknown exception"));
-       }
-}
-
-static void __on_new_failed()
-{
-       static unsigned failCount = 0;
-       _E_ALLOC;
-       failCount += 1;
-       if (failCount >= NEW_FAIL_LIMIT)
-               throw std::bad_alloc();
-}
-
 int main(int argc, char* argv[])
 {
        std::signal(SIGINT, __on_signal);
        std::signal(SIGHUP, __on_signal);
        std::signal(SIGTERM, __on_signal);
        std::signal(SIGQUIT, __on_signal);
-       std::signal(SIGABRT, __on_signal);
-
-       std::set_terminate(__on_terminate);
-       std::set_new_handler(__on_new_failed);
 
        DBusConnector dbusConnector(__bus_acquired, __bus_lost);
 
-       MainLoop::start();
+       __mainLoop.start();
 
        return EXIT_SUCCESS;
 }
diff --git a/src/shared/ServerBase.cpp b/src/shared/ServerBase.cpp
new file mode 100644 (file)
index 0000000..2f60ced
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <new>
+#include <exception>
+#include <stdexcept>
+#include "ServerBase.h"
+
+#define NEW_FAIL_LIMIT 3
+
+using namespace ctx;
+
+static void __on_terminate()
+{
+       try {
+               auto unknown = std::current_exception();
+               if (unknown) {
+                       std::rethrow_exception(unknown);
+               }
+       } catch (const std::exception& e) {
+               _E(RED("Unexpected exception: %s"), e.what());
+       } catch (...) {
+               _E(RED("Unknown exception"));
+       }
+}
+
+static void __on_new_failed()
+{
+       static unsigned failCount = 0;
+       _E_ALLOC;
+       failCount += 1;
+       if (failCount >= NEW_FAIL_LIMIT)
+               throw std::bad_alloc();
+}
+
+MainLoop::MainLoop() :
+       __mainLoop(NULL)
+{
+       std::set_terminate(__on_terminate);
+       std::set_new_handler(__on_new_failed);
+}
+
+bool MainLoop::start()
+{
+       __mainLoop = g_main_loop_new(NULL, FALSE);
+       IF_FAIL_RETURN_TAG(__mainLoop, false, _E, E_STR_ALLOC);
+
+       _I(CYAN("Starting..."));
+       g_main_loop_run(__mainLoop);
+
+       g_main_loop_unref(__mainLoop);
+       __mainLoop = NULL;
+
+       return true;
+}
+
+void MainLoop::stop()
+{
+       if (__mainLoop && g_main_loop_is_running(__mainLoop)) {
+               _I(PURPLE("Terminating..."));
+               g_main_loop_quit(__mainLoop);
+       }
+}
diff --git a/src/shared/ServerBase.h b/src/shared/ServerBase.h
new file mode 100644 (file)
index 0000000..e3bf1e4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONEXT_SERVER_BASE_H__
+#define __CONEXT_SERVER_BASE_H__
+
+#include <ContextTypes.h>
+
+namespace ctx {
+       class MainLoop {
+       public:
+               MainLoop();
+               bool start();
+               void stop();
+       private:
+               GMainLoop* __mainLoop;
+       };
+}
+
+#endif