Fix rpc_port_proxy_destroy() function
[platform/core/appfw/rpc-port.git] / src / proxy-internal.cc
1 /*
2  * Copyright (c) 2017 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 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20
21 #include <aul_svc.h>
22 #include <dlog.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25
26 #include "debug-port-internal.hh"
27 #include "log-private.hh"
28 #include "proxy-internal.h"
29
30 #define EILLEGALACCESS 127
31
32 namespace rpc_port {
33 namespace internal {
34
35 Proxy::Proxy(bool mock)
36     : fd_broker_(new FdBroker(mock)) {}
37
38 Proxy::~Proxy() {
39   _D("Proxy::~Proxy");
40 }
41
42 gboolean Proxy::OnSocketDisconnected(GIOChannel *gio, GIOCondition cond,
43                                      gpointer data) {
44   Proxy* proxy = static_cast<Proxy*>(data);
45   IEventListener* listener = proxy->listener_;
46   int fd = g_io_channel_unix_get_fd(gio);
47
48   _W("Socket was disconnected. fd(%d)", fd);
49
50   if (proxy->main_port_.get()->GetFd() == fd) {
51     proxy->listener_ = nullptr;
52     proxy->main_port_.get()->SetDisconnectedSource(0);
53     if (listener)
54       listener->OnDisconnected(proxy->target_appid_);
55
56     proxy->main_port_.reset();
57     proxy->delegate_port_.reset();
58   } else if (proxy->delegate_port_.get()->GetFd() == fd) {
59     proxy->listener_ = nullptr;
60     proxy->delegate_port_.get()->SetDisconnectedSource(0);
61     if (listener)
62       listener->OnDisconnected(proxy->target_appid_);
63
64     proxy->main_port_.reset();
65     proxy->delegate_port_.reset();
66   }
67   DebugPort::GetInst().RemoveSession(fd);
68
69   return FALSE;
70 }
71
72 gboolean Proxy::OnDataReceived(GIOChannel *gio, GIOCondition cond,
73                                gpointer data) {
74   Proxy* proxy = static_cast<Proxy*>(data);
75   int fd = g_io_channel_unix_get_fd(gio);
76   char buffer[4];
77
78   if (proxy->delegate_port_.get()->GetFd() == fd) {
79     if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
80       _W("Socket was disconnected by stub. fd(%d)", fd);
81       IEventListener* listener = proxy->listener_;
82       proxy->listener_ = nullptr;
83       proxy->delegate_port_.get()->SetSource(0);
84       if (listener)
85         listener->OnDisconnected(proxy->target_appid_);
86
87       DebugPort::GetInst().RemoveSession(proxy->main_port_->GetFd());
88       proxy->main_port_.reset();
89       proxy->delegate_port_.reset();
90       return FALSE;
91     }
92
93     if (proxy->listener_)
94       proxy->listener_->OnReceived(proxy->target_appid_);
95   }
96
97   return TRUE;
98 }
99
100 void Proxy::OnPortRejected(int error) {
101   _W("[__OnPortRejected__] endpoint(%s), error(%d)",
102       target_appid_.c_str(), error);
103   if (listener_ == nullptr)
104     return;
105
106   IEventListener* listener = listener_;
107   listener_ = nullptr;
108   listener->OnRejected(target_appid_, error);
109 }
110
111 void Proxy::OnPortAppeared() {
112   _D("endpoint(%s), port_name(%s)", target_appid_.c_str(), port_name_.c_str());
113   if (listener_ == nullptr)
114     return;
115
116   fds_[0] = 0;
117   fds_[1] = 0;
118   int r = fd_broker_->Send(real_appid_, port_name_, &fds_);
119   if (r <= 0) {
120     // LCOV_EXCL_START
121     IEventListener* listener = listener_;
122     listener_ = nullptr;
123     if (r == -EILLEGALACCESS)
124       listener->OnRejected(target_appid_, RPC_PORT_ERROR_PERMISSION_DENIED);
125     else
126       listener->OnDisconnected(target_appid_);
127     return;
128     // LCOV_EXCL_STOP
129   }
130
131   _W("[__OnPortAppeared__] fds[0]: %d, fds[1]: %d", fds_[0], fds_[1]);
132 }
133
134 void Proxy::OnPortVanished() {
135   _W("[__OnPortVanished__] endpoint(%s), port_name(%s)",
136       target_appid_.c_str(), port_name_.c_str());
137 }
138
139 void Proxy::OnPortConnected() {
140   _W("[__OnPortConnected__] endpoint(%s), port_name(%s)",
141       target_appid_.c_str(), port_name_.c_str());
142   if (!listener_) {
143     _W("listener is null");  // LCOV_EXCL_LINE
144     return;  // LCOV_EXCL_LINE
145   }
146
147   main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false));
148   delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_));
149   listener_->OnConnected(target_appid_, main_port_.get());
150   DebugPort::GetInst().AddSession(port_name_, target_appid_, fds_[0], fds_[1]);
151 }
152
153 // LCOV_EXCL_START
154 void Proxy::OnPortDisconnected(bool cancel) {
155   _W("[__OnPortDisconnected__] endporint(%s), port_name(%s)",
156       target_appid_.c_str(), port_name_.c_str());
157
158   if (cancel) {
159     close(fds_[0]);
160     close(fds_[1]);
161   }
162
163   if (!listener_) {
164     _W("listener is null");
165     return;
166   }
167
168   IEventListener* listener = listener_;
169   listener_ = nullptr;
170   listener->OnDisconnected(target_appid_);
171   DebugPort::GetInst().RemoveSession(fds_[0]);
172 }
173 // LCOV_EXCL_STOP
174
175 int Proxy::Connect(std::string appid, std::string port_name,
176                    IEventListener* ev) {
177   if (ev == nullptr)
178     return RPC_PORT_ERROR_INVALID_PARAMETER;
179
180   if (listener_ != nullptr) {
181     _D("Already connected");  // LCOV_EXCL_LINE
182     return RPC_PORT_ERROR_INVALID_PARAMETER;  // LCOV_EXCL_LINE
183   }
184
185   listener_ = ev;
186   target_appid_ = std::move(appid);
187   port_name_ = std::move(port_name);
188   SetRealAppId(target_appid_);
189
190   int r = fd_broker_->Watch(this, real_appid_, port_name_);
191   if (r < 0) {
192     // LCOV_EXCL_START
193     listener_ = nullptr;
194     if (r == -EILLEGALACCESS)
195       return RPC_PORT_ERROR_PERMISSION_DENIED;
196
197     return RPC_PORT_ERROR_IO_ERROR;
198     // LCOV_EXCL_STOP
199   }
200
201   return RPC_PORT_ERROR_NONE;
202 }
203
204 int Proxy::ConnectSync(std::string appid, std::string port_name,
205                        IEventListener* ev) {
206   if (ev == nullptr)
207     return RPC_PORT_ERROR_INVALID_PARAMETER;
208
209   if (listener_ != nullptr) {
210     _W("Already connected");
211     return RPC_PORT_ERROR_INVALID_PARAMETER;
212   }
213
214   listener_ = ev;
215   target_appid_ = std::move(appid);
216   port_name_ = std::move(port_name);
217   SetRealAppId(target_appid_);
218
219   int ret = fd_broker_->Prepare(real_appid_, port_name_);
220   if (ret < 0) {
221     listener_ = nullptr;
222     if (ret == -EILLEGALACCESS)
223       return RPC_PORT_ERROR_PERMISSION_DENIED;
224
225     return RPC_PORT_ERROR_IO_ERROR;
226   }
227
228   fds_[0] = 0;
229   fds_[1] = 0;
230   ret = fd_broker_->SendSync(real_appid_, port_name_, &fds_);
231   if (ret <= 0) {
232     listener_ = nullptr;
233     if (ret == -EILLEGALACCESS)
234       return RPC_PORT_ERROR_PERMISSION_DENIED;
235
236     return RPC_PORT_ERROR_IO_ERROR;
237   }
238
239   main_port_.reset(new ProxyPort(this, fds_[0], target_appid_, false));
240   delegate_port_.reset(new ProxyPort(this, fds_[1], target_appid_));
241   listener_->OnConnected(target_appid_, main_port_.get());
242   DebugPort::GetInst().AddSession(port_name, target_appid_, fds_[0], fds_[1]);
243
244   return RPC_PORT_ERROR_NONE;
245 }
246
247 void Proxy::DisconnectPort() {
248   main_port_.reset();
249 }
250
251 void Proxy::SetRealAppId(const std::string& alias_appid) {
252   if (!real_appid_.empty())
253     return;
254
255   char* appid = nullptr;
256   int ret = aul_svc_get_appid_by_alias_appid(alias_appid.c_str(), &appid);
257   if (ret != AUL_SVC_RET_OK) {
258     real_appid_ = alias_appid;
259     return;
260   }
261
262   std::unique_ptr<char, decltype(std::free)*> appid_ptr(appid, std::free);
263   real_appid_ = std::string(appid);
264   _W("alias_appid(%s), real_appid(%s)", alias_appid.c_str(), appid);
265 }
266
267 Proxy::ProxyPort::ProxyPort(Proxy* parent, int fd, const std::string& id,
268     bool receive) : Port(fd, id), parent_(parent) {
269   Watch(receive);
270 }
271
272 Proxy::ProxyPort::~ProxyPort() {
273   if (disconn_src_ > 0)
274     g_source_remove(disconn_src_);
275
276   if (src_ > 0)
277     g_source_remove(src_);
278
279   if (gioc_ != nullptr)
280     g_io_channel_unref(gioc_);
281 }
282
283 int Proxy::ProxyPort::Watch(bool receive) {
284   char buf[1024];
285   int fd = GetFd();
286
287   gioc_ = g_io_channel_unix_new(fd);
288   if (!gioc_) {
289     _E("Error is %s", strerror_r(errno, buf, sizeof(buf)));  // LCOV_EXCL_LINE
290     return -1;  // LCOV_EXCL_LINE
291   }
292
293   disconn_src_ = g_io_add_watch(gioc_,
294       (GIOCondition)(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
295       Proxy::OnSocketDisconnected, parent_);
296   if (disconn_src_ == 0) {
297     // LCOV_EXCL_START
298     _E("Failed to add watch on socket");
299     g_io_channel_unref(gioc_);
300     gioc_ = nullptr;
301     return -1;
302     // LCOV_EXCL_STOP
303   }
304
305   if (!receive)
306     return 0;
307
308   src_ = g_io_add_watch(gioc_,
309       (GIOCondition)(G_IO_IN),
310       Proxy::OnDataReceived, parent_);
311   if (src_ == 0) {
312     // LCOV_EXCL_START
313     _E("Failed to add watch on socket");
314     g_source_remove(disconn_src_);
315     disconn_src_ = 0;
316     g_io_channel_unref(gioc_);
317     gioc_ = nullptr;
318     return -1;
319     // LCOV_EXCL_STOP
320   }
321
322   return 0;
323 }
324
325 void Proxy::ProxyPort::SetDisconnectedSource(int sourceId) {
326   disconn_src_ = sourceId;
327 }
328
329 void Proxy::ProxyPort::SetSource(int sourceId) {
330   src_ = sourceId;
331 }
332
333 }  // namespace internal
334 }  // namespace rpc_port