2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <sys/socket.h>
21 #include <systemd/sd-daemon.h>
23 #include <IAgentPlugin.h>
24 #include "PluginLoader.h"
25 #include "AgentSocket.h"
27 #define PATH_LENGTH 48
28 #define TERM_MSG_ID 0xFFFF
33 PluginLoader* pluginLoader;
38 CommandInfo(PluginLoader* loader, uint16_t i, uint8_t len, char* cmd) :
39 pluginLoader(loader), id(i), length(len), command(NULL)
41 command = malloc(length);
44 throw std::bad_alloc();
46 memcpy(command, cmd, length);
55 static gboolean __send_command(gpointer data)
57 CommandInfo* info = static_cast<CommandInfo*>(data);
59 info->pluginLoader->send(info->id, info->length, info->command);
63 return G_SOURCE_REMOVE;
66 static bool __set_close_on_exec(int fd)
68 if (::fcntl(fd, F_SETFL, FD_CLOEXEC) == -1)
74 static int __get_socket_fd(const char* path)
76 int n = sd_listen_fds(0);
77 IF_FAIL_RETURN_TAG(n > 0, E_ACCESS, _E, "sd_listen_fds() failed");
79 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
80 if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path, 0) > 0) {
81 __set_close_on_exec(fd);
89 AgentSocket::AgentSocket(PluginLoader& loader) :
92 __listeningThread(NULL),
93 __pluginLoader(loader)
97 throw std::runtime_error("Socket connection failed");
103 AgentSocket::~AgentSocket()
108 bool AgentSocket::__init()
110 char path[PATH_LENGTH];
111 g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
113 _D("Socket Path: %s", path);
115 __sockFd = __get_socket_fd(path);
116 IF_FAIL_RETURN_TAG(__sockFd > 0, false, _E, "Failed to get the socket fd");
118 __listening.store(true);
119 __listeningThread = g_thread_new(NULL, __listen, this);
120 IF_FAIL_RETURN_TAG(__listeningThread, false, _E, "Thread creation failed");
125 gpointer AgentSocket::__listen(gpointer data)
127 static_cast<AgentSocket*>(data)->__listen();
131 void AgentSocket::__listen()
135 while (__listening.load()) {
136 msgsock = accept(__sockFd, 0, 0);
139 _D("accept() failed");
143 if (!__readCommand(msgsock)) {
152 bool AgentSocket::__readCommand(int msgsock)
156 char command[CTX_AGENT_COMMAND_LIMIT] = {0};
158 auto safeRead = [&msgsock](char* buf, size_t count)->bool {
160 int rc = read(msgsock, buf, count);
162 if (errno == EAGAIN) {
165 _E("Socket read error: %d", errno);
177 success = safeRead(reinterpret_cast<char*>(&id), sizeof(id));
178 IF_FAIL_RETURN(success, false);
180 if (id == TERM_MSG_ID) {
181 _D("Stop listening...");
185 success = safeRead(reinterpret_cast<char*>(&length), sizeof(length));
186 IF_FAIL_RETURN(success, false);
187 IF_FAIL_RETURN_TAG(length > 0 && length <= CTX_AGENT_COMMAND_LIMIT, false, _E, "Invalid command");
189 success = safeRead(command, length);
190 IF_FAIL_RETURN(success, false);
192 CommandInfo* info = new CommandInfo(&__pluginLoader, id, length, command);
193 g_idle_add(__send_command, info);
198 void AgentSocket::__release()
200 if (!__listening.load())
203 __listening.store(false);
206 if (__listeningThread)
207 g_thread_join(__listeningThread);
212 bool AgentSocket::__terminate()
216 char path[PATH_LENGTH];
217 const uint16_t termMsg = TERM_MSG_ID;
219 g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
220 IF_FAIL_RETURN_TAG(strlen(path) < sizeof(addr.sun_path), false, _E, "Invalid path");
222 sock = socket(AF_UNIX, SOCK_STREAM, 0);
223 IF_FAIL_RETURN_TAG(sock > 0, false, _E, "socket creation failed");
225 bzero(&addr, sizeof(addr));
226 addr.sun_family = AF_UNIX;
227 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
228 addr.sun_path[sizeof(path)] = '\0';
230 if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
232 _E("Connection failed");
236 if (write(sock, &termMsg, sizeof(termMsg)) < 0) {
238 _E("Sending failed");