Fix retrieving app com connections
[platform/core/appfw/aul-1.git] / src / app_com.cc
1 /*
2  * Copyright (c) 2015 - 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
20 #include <list>
21 #include <mutex>
22 #include <string>
23
24 #include "aul_api.h"
25 #include "aul_util.h"
26 #include "include/aul.h"
27 #include "include/aul_app_com.h"
28 #include "include/aul_cmd.h"
29 #include "launch.h"
30
31 namespace {
32
33 class AppComConnection {
34  public:
35   AppComConnection(std::string endpoint, app_com_cb cb, void* user_data)
36       : endpoint_(std::move(endpoint)),
37         cb_(cb),
38         user_data_(user_data) {
39   }
40
41   ~AppComConnection() = default;
42
43   const std::string& GetEndpoint() const {
44     return endpoint_;
45   }
46
47   void Invoke(aul_app_com_result_e result, bundle* envelope) {
48     if (cb_)
49       cb_(endpoint_.c_str(), result, envelope, user_data_);
50   }
51
52  private:
53   std::string endpoint_;
54   app_com_cb cb_;
55   void* user_data_;
56 };
57
58 class AppComPermission {
59  public:
60   AppComPermission() {}
61   ~AppComPermission() {}
62
63   void SetPrivilege(std::string privilege) {
64     privilege_ = std::move(privilege);
65   }
66
67   void SetPropagationOption(aul_app_com_propagate_option_e option) {
68     option_ = option;
69   }
70
71   const std::string& GetPrivilege() const {
72     return privilege_;
73   }
74
75   aul_app_com_propagate_option_e GetPropagationOption() const {
76     return option_;
77   }
78
79  private:
80   std::string privilege_;
81   aul_app_com_propagate_option_e option_;
82 };
83
84 class Context {
85  public:
86   Context() {}
87   ~Context() {}
88
89   int Receive(bundle* b) {
90     const char* val = bundle_get_val(b, AUL_K_COM_ENDPOINT);
91     if (val == nullptr)
92       return -1;
93
94     size_t result_size = 0;
95     aul_app_com_result_e* result = nullptr;
96     int ret = bundle_get_byte(b, AUL_K_COM_RESULT,
97         reinterpret_cast<void**>(&result), &result_size);
98     if (ret != BUNDLE_ERROR_NONE)
99       return -1;
100
101     std::string endpoint(val);
102
103     std::lock_guard<std::recursive_mutex> lock(mutex_);
104     auto iter = conns_.begin();
105     while (iter != conns_.end()) {
106       auto& conn = *iter;
107       iter++;
108       if (conn->GetEndpoint() == endpoint)
109         conn->Invoke(*result, b);
110     }
111
112     return 0;
113   }
114
115   AppComConnection* AddConnection(std::string endpoint, app_com_cb cb,
116       void* user_data) {
117     auto* conn = new (std::nothrow) AppComConnection(endpoint, cb, user_data);
118     if (conn == nullptr)
119       return nullptr;
120
121     std::lock_guard<std::recursive_mutex> lock(mutex_);
122     conns_.emplace_back(conn);
123     return conn;
124   }
125
126   void RemoveConnection(AppComConnection* conn) {
127     std::lock_guard<std::recursive_mutex> lock(mutex_);
128     auto iter = conns_.begin();
129     while (iter != conns_.end()) {
130       if ((*iter).get() == conn) {
131         iter = conns_.erase(iter);
132         break;
133       } else {
134         iter++;
135       }
136     }
137   }
138
139   bool ExistConnection(const std::string& endpoint) {
140     std::lock_guard<std::recursive_mutex> lock(mutex_);
141     for (auto& conn : conns_) {
142       if (conn->GetEndpoint() == endpoint)
143         return true;
144     }
145
146     return false;
147   }
148
149   bool ExistConnection(AppComConnection* conn) {
150     std::lock_guard<std::recursive_mutex> lock(mutex_);
151     for (auto& i : conns_) {
152       if (i.get() == conn)
153         return true;
154     }
155
156     return false;
157   }
158
159  private:
160   std::list<std::unique_ptr<AppComConnection>> conns_;
161   mutable std::recursive_mutex mutex_;
162 };
163
164 Context context;
165
166 }  // namespace
167
168 int app_com_recv(bundle* b) {
169   if (b == nullptr)
170     return -1;
171
172   return context.Receive(b);
173 }
174
175 extern "C" API aul_app_com_permission_h aul_app_com_permission_create() {
176   auto* handle = new (std::nothrow) AppComPermission();
177   return static_cast<aul_app_com_permission_h>(handle);
178 }
179
180 extern "C" API void aul_app_com_permission_destroy(
181     aul_app_com_permission_h permission) {
182   if (permission == nullptr)
183     return;
184
185   auto* handle = static_cast<AppComPermission*>(permission);
186   delete handle;
187 }
188
189 extern "C" API int aul_app_com_permission_set_propagation(
190     aul_app_com_permission_h permission,
191     aul_app_com_propagate_option_e option) {
192   if (permission == nullptr)
193     return AUL_R_EINVAL;
194
195   auto* handle = static_cast<AppComPermission*>(permission);
196   handle->SetPropagationOption(option);
197   return AUL_R_OK;
198 }
199
200 extern "C" API int aul_app_com_permission_set_privilege(
201     aul_app_com_permission_h permission, const char* privilege) {
202   if (permission == nullptr || privilege == nullptr)
203     return AUL_R_EINVAL;
204
205   auto* handle = static_cast<AppComPermission*>(permission);
206   handle->SetPrivilege(privilege);
207   return AUL_R_OK;
208 }
209
210 static int AppComCreate(const char* endpoint,
211     aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
212     bool sync, aul_app_com_connection_h* connection) {
213   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
214     _E("Invalid parameter");
215     return AUL_R_EINVAL;
216   }
217
218   if (!aul_is_initialized()) {
219     if (aul_launch_init(nullptr, nullptr) < 0)
220       return AUL_R_ENOINIT;
221   }
222
223   tizen_base::Bundle b;
224   b.Add(AUL_K_COM_ENDPOINT, endpoint);
225
226   if (permission) {
227     auto* handle = static_cast<AppComPermission*>(permission);
228     auto option = handle->GetPropagationOption();
229     if (option) {
230       auto* p = reinterpret_cast<unsigned char*>(&option);
231       std::vector<unsigned char> bytes;
232       std::copy(p, p + sizeof(option), std::back_inserter(bytes));
233       b.Add(AUL_K_COM_PROPAGATE, bytes);
234     }
235
236     if (!handle->GetPrivilege().empty())
237       b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
238   }
239
240   int ret;
241   if (sync) {
242     ret = app_send_cmd(AUL_UTIL_PID, APP_COM_CREATE, b.GetHandle());
243   } else {
244     ret = app_send_cmd_with_noreply(AUL_UTIL_PID, APP_COM_CREATE,
245         b.GetHandle());
246   }
247
248   if (ret == 0) {
249     *connection = static_cast<aul_app_com_connection_h>(
250         context.AddConnection(endpoint, callback, user_data));
251   }
252
253   return ret;
254 }
255
256 extern "C" API int aul_app_com_create(const char* endpoint,
257     aul_app_com_permission_h permission, app_com_cb callback,
258     void* user_data, aul_app_com_connection_h* connection) {
259   return AppComCreate(endpoint, permission, callback, user_data,
260       true, connection);
261 }
262
263 extern "C" API int aul_app_com_create_async(const char* endpoint,
264     aul_app_com_permission_h permission, app_com_cb callback,
265     void* user_data, aul_app_com_connection_h* connection) {
266   return AppComCreate(endpoint, permission, callback, user_data,
267       false, connection);
268 }
269
270 extern "C" API int aul_app_com_join(const char* endpoint, const char* filter,
271     app_com_cb callback, void* user_data,
272     aul_app_com_connection_h* connection) {
273   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
274     _E("Invalid parameter");
275     return AUL_R_EINVAL;
276   }
277
278   if (!aul_is_initialized()) {
279     if (aul_launch_init(nullptr, nullptr) < 0)
280       return AUL_R_ENOINIT;
281   }
282
283   tizen_base::Bundle b;
284   b.Add(AUL_K_COM_ENDPOINT, endpoint);
285   if (filter)
286     b.Add(AUL_K_COM_FILTER, filter);
287
288   int ret = app_send_cmd(AUL_UTIL_PID, APP_COM_JOIN, b.GetHandle());
289   if (ret == 0) {
290     *connection = static_cast<aul_app_com_connection_h>(
291         context.AddConnection(endpoint, callback, user_data));
292   }
293
294   return ret;
295 }
296
297 extern "C" API int aul_app_com_send(const char* endpoint, bundle* envelope) {
298   if (endpoint == nullptr || envelope == nullptr)
299     return AUL_R_EINVAL;
300
301   bundle_del(envelope, AUL_K_COM_ENDPOINT);
302   bundle_add(envelope, AUL_K_COM_ENDPOINT, endpoint);
303   return app_send_cmd(AUL_UTIL_PID, APP_COM_SEND, envelope);
304 }
305
306 extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
307   if (connection == nullptr)
308     return AUL_R_EINVAL;
309
310   auto* conn = static_cast<AppComConnection*>(connection);
311   if (!context.ExistConnection(conn)) {
312     _E("Invalid parameter");
313     return AUL_R_EINVAL;
314   }
315
316   std::string endpoint = conn->GetEndpoint();
317   context.RemoveConnection(conn);
318
319   if (context.ExistConnection(endpoint))
320     return AUL_R_OK;
321
322   tizen_base::Bundle b;
323   b.Add(AUL_K_COM_ENDPOINT, endpoint);
324   return app_send_cmd(AUL_UTIL_PID, APP_COM_LEAVE, b.GetHandle());
325 }