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.
18 #include <sys/socket.h>
20 #include <systemd/sd-daemon.h>
22 #include <IAgentPlugin.h>
23 #include "PluginLoader.h"
24 #include "AgentSocket.h"
26 #define PATH_LENGTH 48
27 #define TERM_MSG_ID 0xFFFF
32 PluginLoader* pluginLoader;
37 CommandInfo(PluginLoader* loader, uint16_t i, uint8_t len, char* cmd) :
38 pluginLoader(loader), id(i), length(len), command(NULL)
40 command = malloc(length);
43 throw std::bad_alloc();
45 memcpy(command, cmd, length);
54 static gboolean __send_command(gpointer data)
56 CommandInfo* info = static_cast<CommandInfo*>(data);
58 info->pluginLoader->send(info->id, info->length, info->command);
62 return G_SOURCE_REMOVE;
65 static bool __set_close_on_exec(int fd)
67 if (::fcntl(fd, F_SETFL, FD_CLOEXEC) == -1)
73 static int __get_socket_fd(const char* path)
75 int n = sd_listen_fds(0);
76 IF_FAIL_RETURN_TAG(n > 0, E_ACCESS, _E, "sd_listen_fds() failed");
78 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
79 if (sd_is_socket_unix(fd, SOCK_STREAM, 1, path, 0) > 0) {
80 __set_close_on_exec(fd);
88 AgentSocket::AgentSocket(PluginLoader& loader) :
91 __listeningThread(NULL),
92 __pluginLoader(loader)
96 throw std::runtime_error("Socket connection failed");
102 AgentSocket::~AgentSocket()
107 bool AgentSocket::__init()
109 char path[PATH_LENGTH];
110 g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
112 _D("Socket Path: %s", path);
114 __sockFd = __get_socket_fd(path);
115 IF_FAIL_RETURN_TAG(__sockFd > 0, false, _E, "Failed to get the socket fd");
117 __listening.store(true);
118 __listeningThread = g_thread_new(NULL, __listen, this);
119 IF_FAIL_RETURN_TAG(__listeningThread, false, _E, "Thread creation failed");
124 gpointer AgentSocket::__listen(gpointer data)
126 static_cast<AgentSocket*>(data)->__listen();
130 void AgentSocket::__listen()
134 while (__listening.load()) {
135 msgsock = accept(__sockFd, 0, 0);
138 _D("accept() failed");
142 if (!__readCommand(msgsock)) {
151 bool AgentSocket::__readCommand(int msgsock)
156 char buf[CTX_AGENT_COMMAND_LIMIT] = {0};
158 rval = read(msgsock, &id, sizeof(id));
159 IF_FAIL_RETURN_TAG(rval == sizeof(id), false, _E, "read() failed");
161 if (id == TERM_MSG_ID) {
162 _D("Stop listening...");
166 rval = read(msgsock, &length, sizeof(length));
167 IF_FAIL_RETURN_TAG(rval == sizeof(length), false, _E, "read() failed");
169 rval = read(msgsock, buf, length);
170 IF_FAIL_RETURN_TAG(rval == static_cast<int>(length), false, _E, "read() failed");
175 CommandInfo* info = new CommandInfo(&__pluginLoader, id, length, buf);
176 g_idle_add(__send_command, info);
181 void AgentSocket::__release()
183 if (!__listening.load())
186 __listening.store(false);
189 if (__listeningThread)
190 g_thread_join(__listeningThread);
195 bool AgentSocket::__terminate()
199 char path[PATH_LENGTH];
200 const uint16_t termMsg = TERM_MSG_ID;
202 g_snprintf(path, PATH_LENGTH, CTX_AGENT_SOCKET, static_cast<unsigned>(getuid()));
203 IF_FAIL_RETURN_TAG(strlen(path) < sizeof(addr.sun_path), false, _E, "Invalid path");
205 sock = socket(AF_UNIX, SOCK_STREAM, 0);
206 IF_FAIL_RETURN_TAG(sock > 0, false, _E, "socket creation failed");
208 bzero(&addr, sizeof(addr));
209 addr.sun_family = AF_UNIX;
210 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
211 addr.sun_path[sizeof(path)] = '\0';
213 if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
215 _E("Connection failed");
219 if (write(sock, &termMsg, sizeof(termMsg)) < 0) {
221 _E("Sending failed");