Move function definition to aul header
[platform/core/appfw/aul-1.git] / src / aul_rpc_port.cc
1 /*
2  * Copyright (c) 2018 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <bundle_cpp.h>
18 #include <bundle_internal.h>
19 #include <glib.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <memory>
25 #include <string>
26
27 #include "app_request.h"
28 #include "aul_api.h"
29 #include "aul_util.h"
30 #include "include/aul.h"
31 #include "include/aul_app_com.h"
32 #include "include/aul_error.h"
33 #include "include/aul_rpc_port.h"
34 #include "include/aul_sock.h"
35 #include "include/aul_svc.h"
36
37 using namespace aul::internal;
38
39 namespace {
40
41 constexpr const char kEndpoint[] = "org.tizen.rpcport";
42 constexpr const char kInterfacePrefix[] = "org.tizen.rpcport._";
43 constexpr const char kPathRunAulRpcPort[] = "/run/aul/rpcport/";
44
45 class WatchInfo {
46  public:
47   WatchInfo(std::string app_id, std::string port_name,
48       aul_rpc_port_appeared_cb appeared_cb,
49       aul_rpc_port_vanished_cb vanished_cb,
50       void* user_data, uid_t uid)
51       : app_id_(std::move(app_id)),
52         port_name_(std::move(port_name)),
53         appeared_cb_(appeared_cb),
54         vanished_cb_(vanished_cb),
55         user_data_(user_data),
56         uid_(uid) {
57   }
58
59   ~WatchInfo() {}
60
61   int Watch() {
62     int ret = aul_app_com_create(kEndpoint, nullptr, AppComCb, this, &conn_);
63     if (ret != AUL_R_OK)
64       _E("aul_app_com_create() is failed. error(%d)", ret);
65
66     return ret;
67   }
68
69   void Unwatch() {
70     if (conn_) {
71       aul_app_com_leave(conn_);
72       conn_ = nullptr;
73     }
74   }
75
76  private:
77   static int AppComCb(const char* endpoint, aul_app_com_result_e result,
78       bundle* envelope, void* user_data) {
79     auto* info = static_cast<WatchInfo*>(user_data);
80     tizen_base::Bundle b(envelope, false, false);
81     std::string app_id = b.GetString(AUL_K_APPID);
82     if (info->app_id_ != app_id)
83       return -1;
84
85     std::string port_name = b.GetString(AUL_K_RPC_PORT);
86     if (info->port_name_ != port_name)
87       return -1;
88
89     std::string uid_str = b.GetString(AUL_K_CALLER_UID);
90     uid_t uid =
91         static_cast<uid_t>(std::stoul(uid_str, nullptr, 10) & UINT32_MAX);
92     if (info->uid_ != uid)
93       return -1;
94
95     std::string pid_str = b.GetString(AUL_K_PID);
96     int pid = std::stoi(pid_str);
97     std::string event_name = b.GetString(AUL_K_EVENT_NAME);
98     if (event_name == "Appeared") {
99       info->appeared_cb_(app_id.c_str(), port_name.c_str(), pid,
100           info->user_data_);
101     } else {
102       info->vanished_cb_(app_id.c_str(), port_name.c_str(), pid,
103           info->user_data_);
104     }
105
106     return 0;
107   }
108
109  private:
110   std::string app_id_;
111   std::string port_name_;
112   aul_rpc_port_appeared_cb appeared_cb_;
113   aul_rpc_port_vanished_cb vanished_cb_;
114   void* user_data_;
115   uid_t uid_;
116   aul_app_com_connection_h conn_ = nullptr;
117 };
118
119 std::string GetInterfaceName(const std::string& app_id,
120     const std::string& port_name, uid_t uid) {
121   std::string name = kInterfacePrefix + app_id + "_" + port_name;
122   char* checksum = g_compute_checksum_for_string(G_CHECKSUM_SHA1,
123       name.c_str(), name.length());
124   std::unique_ptr<char, decltype(g_free)*> checksum_auto(checksum, g_free);
125   return std::to_string(uid) + "@" + std::string(checksum);
126 }
127
128 std::string GetPath(const std::string& interface_name) {
129   return std::string(kPathRunAulRpcPort) + "." + interface_name;
130 }
131
132 }  // namespace
133
134 extern "C" API int aul_rpc_port_prepare_stub(const char* app_id,
135     const char* port_name) {
136   return aul_rpc_port_usr_prepare_stub(app_id, port_name, getuid());
137 }
138
139 extern "C" API int aul_rpc_port_usr_prepare_stub(const char* app_id,
140     const char* port_name, uid_t uid) {
141   if (app_id == nullptr || port_name == nullptr) {
142     _E("Invalid parameter");
143     return AUL_R_EINVAL;
144   }
145
146   tizen_base::Bundle b {{AUL_K_RPC_PORT, port_name}};
147   int ret = AppRequest(RPC_PORT_PREPARE_STUB, uid)
148       .With(b)
149       .SetAppId(app_id)
150       .SendSimply(AUL_SOCK_QUEUE);
151   if (ret < 0) {
152     _E("Failed to send request. app_id(%s), port_name(%s)", app_id, port_name);
153     return ret;
154   }
155
156   return AUL_R_OK;
157 }
158
159 extern "C" API int aul_rpc_port_create_socket_pair(const char* app_id,
160     const char* port_name, int (*fds)[2]) {
161   if (app_id == nullptr || port_name == nullptr || fds == nullptr) {
162     _E("Invalid parameter");
163     return AUL_R_EINVAL;
164   }
165
166   tizen_base::Bundle b {{AUL_K_RPC_PORT, port_name}};
167   int fd = AppRequest(RPC_PORT_CREATE_SOCKET_PAIR, getuid())
168       .With(b)
169       .SetAppId(app_id)
170       .SendSimply(AUL_SOCK_ASYNC);
171   if (fd <= 0 || fd >= sysconf(_SC_OPEN_MAX)) {
172     _E("Failed to send socket pair creation request. error(%d)", fd);
173     return fd;
174   }
175
176   int ret = aul_sock_recv_reply_sock_fd(fd, fds, 2);
177   if (ret != 0) {
178     _E("Failed to receive socket fds. error(%d)", ret);
179     return aul_error_convert(ret);
180   }
181
182   return AUL_R_OK;
183 }
184
185 extern "C" API int aul_rpc_port_notify_rpc_finished(void) {
186   int ret = AppRequest(RPC_PORT_NOTIFY_RPC_FINISHED, getuid())
187       .SetPid(getpid())
188       .SendSimply(AUL_SOCK_NOREPLY);
189   if (ret != 0) {
190     _E("Failed to notify rpc finished. error(%d)", ret);
191     return ret;
192   }
193
194   return AUL_R_OK;
195 }
196
197 extern "C" API int aul_rpc_port_set_private_sharing(const char* app_id,
198     const char* paths[], unsigned int size) {
199   if (app_id == nullptr || paths == nullptr) {
200     _E("Invalid parameter");
201     return AUL_R_EINVAL;
202   }
203
204   tizen_base::Bundle b {{AUL_K_CALLEE_APPID, app_id}};
205   std::vector<std::string> v;
206   for (unsigned int i = 0; i < size; ++i)
207     v.push_back(paths[i]);
208   b.Add(AUL_SVC_DATA_PATH, v);
209
210   int ret = AppRequest(SET_PRIVATE_SHARING, getuid())
211       .With(b)
212       .SetPid(getpid())
213       .SendSimply(AUL_SOCK_NOREPLY);
214   if (ret != 0) {
215     _E("Failed to set private sharing. error(%d)", ret);
216     return ret;
217   }
218
219   return AUL_R_OK;
220 }
221
222 extern "C" API int aul_rpc_port_unset_private_sharing(const char* app_id) {
223   if (app_id == nullptr) {
224     _E("Invalid parameter");
225     return AUL_R_EINVAL;
226   }
227
228   tizen_base::Bundle b {{AUL_K_CALLEE_APPID, app_id}};
229   int ret = AppRequest(UNSET_PRIVATE_SHARING, getuid())
230       .With(b)
231       .SetPid(getpid())
232       .SendSimply(AUL_SOCK_NOREPLY);
233   if (ret != 0) {
234     _E("Failed to unset private sharing. error(%d)", ret);
235     return ret;
236   }
237
238   return AUL_R_OK;
239 }
240
241 extern "C" API int aul_rpc_port_create(const char* port_name, int* fd) {
242   return aul_rpc_port_usr_create(port_name, getuid(), fd);
243 }
244
245 extern "C" API int aul_rpc_port_usr_create(const char* port_name, uid_t uid,
246     int* fd) {
247   if (port_name == nullptr || fd == nullptr) {
248     _E("Invalid paramter");
249     return AUL_R_EINVAL;
250   }
251
252   tizen_base::Bundle b {{AUL_K_RPC_PORT, port_name}};
253   int req_fd = AppRequest(RPC_PORT_CREATE, uid)
254       .With(b)
255       .SendSimply(AUL_SOCK_ASYNC);
256   if (req_fd <= 0 || req_fd >= sysconf(_SC_OPEN_MAX)) {
257     _E("Failed to send socket creation request. error(%d)", req_fd);
258     return req_fd;
259   }
260
261   int fds[2] = { -1, };
262   int ret = aul_sock_recv_reply_sock_fd(req_fd, &fds, 1);
263   if (ret != 0) {
264     _E("Failed to receive socket fds. error(%d)", ret);
265     return aul_error_convert(ret);
266   }
267
268   *fd = fds[0];
269   return AUL_R_OK;
270 }
271
272 extern "C" API int aul_rpc_port_destroy(const char* port_name) {
273   return aul_rpc_port_usr_destroy(port_name, getuid());
274 }
275
276 extern "C" API int aul_rpc_port_usr_destroy(const char* port_name, uid_t uid) {
277   if (port_name == nullptr) {
278     _E("Invalid parameter");
279     return AUL_R_EINVAL;
280   }
281
282   tizen_base::Bundle b {{AUL_K_RPC_PORT, port_name}};
283   int ret = AppRequest(RPC_PORT_DESTROY, uid)
284       .With(b)
285       .SendSimply(AUL_SOCK_NOREPLY);
286   if (ret != 0) {
287     _E("Failed to send socket desctruction request. error(%d)", ret);
288     return ret;
289   }
290
291   return AUL_R_OK;
292 }
293
294 extern "C" API int aul_rpc_port_add_watch(const char* app_id,
295     const char* port_name, aul_rpc_port_appeared_cb appeared_cb,
296     aul_rpc_port_vanished_cb vanished_cb, void* user_data,
297     aul_rpc_port_watch_h* handle) {
298   return aul_rpc_port_usr_add_watch(app_id, port_name, appeared_cb, vanished_cb,
299       user_data, getuid(), handle);
300 }
301
302 extern "C" API int aul_rpc_port_usr_add_watch(const char* app_id,
303     const char* port_name, aul_rpc_port_appeared_cb appeared_cb,
304     aul_rpc_port_vanished_cb vanished_cb, void* user_data, uid_t uid,
305     aul_rpc_port_watch_h* handle) {
306   if (app_id == nullptr || port_name == nullptr || appeared_cb == nullptr ||
307       vanished_cb == nullptr || handle == nullptr) {
308     _E("Invalid parameter");
309     return AUL_R_EINVAL;
310   }
311
312   auto* info = new (std::nothrow) WatchInfo(app_id, port_name, appeared_cb,
313       vanished_cb, user_data, uid);
314   if (info == nullptr) {
315     _E("Out of memory");
316     return AUL_R_ENOMEM;
317   }
318
319   int ret = info->Watch();
320   if (ret != AUL_R_OK) {
321     delete info;
322     return ret;
323   }
324
325   *handle = static_cast<aul_rpc_port_watch_h>(info);
326   return AUL_R_OK;
327 }
328
329 extern "C" API int aul_rpc_port_remove_watch(aul_rpc_port_watch_h handle) {
330   if (handle == nullptr) {
331     _E("Invalid parameter");
332     return AUL_R_EINVAL;
333   }
334
335   auto* info = static_cast<WatchInfo*>(handle);
336   info->Unwatch();
337   delete info;
338   return AUL_R_OK;
339 }
340
341 extern "C" API int aul_rpc_port_exist(const char* app_id, const char* port_name,
342     bool* exist) {
343   return aul_rpc_port_usr_exist(app_id, port_name, getuid(), exist);
344 }
345
346 extern "C" API int aul_rpc_port_usr_exist(const char* app_id,
347     const char* port_name, uid_t uid, bool* exist) {
348   if (app_id == nullptr || port_name == nullptr || exist == nullptr) {
349     _E("Invalid parameter");
350     return AUL_R_EINVAL;
351   }
352
353   char* port_path;
354   if (aul_rpc_port_usr_get_path(app_id, port_name, uid, &port_path) != AUL_R_OK)
355     return AUL_R_ENOMEM;
356
357   int ret = access(port_path, F_OK);
358   free(port_path);
359   *exist = (ret == 0) ? true : false;
360   return AUL_R_OK;
361 }
362
363 extern "C" API int aul_rpc_port_get_path(const char* app_id,
364     const char* port_name, char** path) {
365   return aul_rpc_port_usr_get_path(app_id, port_name, getuid(), path);
366 }
367
368 extern "C" API int aul_rpc_port_usr_get_path(const char* app_id,
369     const char* port_name, uid_t uid, char** path) {
370   if (app_id == nullptr || port_name == nullptr || path == nullptr) {
371     _E("Invalid parameter");
372     return AUL_R_EINVAL;
373   }
374
375   std::string interface_name = GetInterfaceName(app_id, port_name, uid);
376   std::string port_path = GetPath(interface_name);
377   struct sockaddr_un addr = { 0, };
378   snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", port_path.c_str());
379   *path = strdup(addr.sun_path);
380   if (*path == nullptr) {
381     _E("Out of memory");
382     return AUL_R_ENOMEM;
383   }
384
385   return AUL_R_OK;
386 }