2 * Copyright (c) 2020 - 2021 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.
17 #include "debug-port-internal.hh"
19 #include <aul_app_com.h>
20 #include <bundle_internal.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
36 #include "log-private.hh"
37 #include "port-internal.hh"
38 #include "shared-queue-internal.hh"
44 constexpr const char PATH_RPC_PORT_UTIL_SOCK[] =
45 "/run/aul/daemons/.rpc-port-util-sock";
46 constexpr const char ENDPOINT_RPC_PORT_DEBUG[] = "org.tizen.rpcport.debug";
47 constexpr const char KEY_PORT_NAME[] = "__K_PORT_NAME__";
51 Session(std::string port_name, std::string destination,
52 int main_port, int delegate_port)
53 : port_name_(std::move(port_name)),
54 destination_(std::move(destination)),
55 main_port_(main_port),
56 delegate_port_(delegate_port) {
59 const std::string& GetPortName() const {
63 const std::string& GetDestination() const {
67 int GetMainPort() const {
71 int GetDelegatePort() const {
72 return delegate_port_;
76 std::string port_name_;
77 std::string destination_;
84 DebugPortImpl() = default;
88 bool IsConnected() const;
89 void AddSession(std::string port_name, std::string destination,
90 int main_port, int delegate_port);
91 void RemoveSession(int port);
92 int Send(int port, bool is_read, uint32_t seq,
93 const void* buf, unsigned int size);
100 void SetConnectionStatus(bool status);
104 std::recursive_mutex& GetMutex() const;
105 std::shared_ptr<Session> FindSession(int port);
106 std::shared_ptr<Session> FindSession(const std::string& port_name);
108 static gboolean OnDebugPortDisconnectedCb(GIOChannel* io,
109 GIOCondition cond, gpointer data);
110 static int AppComCb(const char* endpoint, aul_app_com_result_e result,
111 bundle* envelope, void* user_data);
114 bool disposed_ = true;
115 std::atomic<bool> connected_ { false };
116 std::unique_ptr<Port> port_;
117 GIOChannel* io_ = nullptr;
118 guint watch_tag_ = 0;
119 std::list<std::shared_ptr<Session>> sessions_;
121 std::atomic<bool> is_running_ { false };
122 SharedQueue<std::shared_ptr<tizen_base::Parcel>> queue_;
123 mutable std::recursive_mutex mutex_;
124 aul_app_com_connection_h conn_ = nullptr;
127 DebugPortImpl::~DebugPortImpl() {
131 void DebugPortImpl::Dispose() {
132 std::lock_guard<std::recursive_mutex> lock(GetMutex());
137 aul_app_com_leave(conn_);
146 bool DebugPortImpl::IsConnected() const {
150 void DebugPortImpl::AddSession(std::string port_name, std::string destination,
151 int main_port, int delegate_port) {
152 std::lock_guard<std::recursive_mutex> lock(GetMutex());
153 sessions_.emplace_back(
154 new Session(std::move(port_name), std::move(destination),
155 main_port, delegate_port));
158 void DebugPortImpl::RemoveSession(int port) {
159 std::lock_guard<std::recursive_mutex> lock(GetMutex());
160 auto iter = std::find_if(sessions_.begin(), sessions_.end(),
161 [port](std::shared_ptr<Session>& sess) -> bool {
162 return sess->GetMainPort() == port || sess->GetDelegatePort() == port;
165 if (iter != sessions_.end()) {
166 _W("Remove session. port(%d)", port);
167 iter = sessions_.erase(iter);
171 std::shared_ptr<Session> DebugPortImpl::FindSession(int port) {
172 std::lock_guard<std::recursive_mutex> lock(GetMutex());
173 for (auto& s : sessions_) {
174 if (s->GetMainPort() == port || s->GetDelegatePort() == port)
181 std::shared_ptr<Session> DebugPortImpl::FindSession(
182 const std::string& port_name) {
183 std::lock_guard<std::recursive_mutex> lock(GetMutex());
184 for (auto& s : sessions_) {
185 if (s->GetPortName() == port_name)
192 int DebugPortImpl::Send(int port, bool is_read, uint32_t seq,
193 const void* buf, unsigned int size) {
197 auto session = FindSession(port);
198 if (session == nullptr) {
199 _E("Failed to find session. port(%d)", port);
203 // time + port_name + destination + is_delegate + port + is_read + seq + size + data
204 tizen_base::Parcel parcel;
205 parcel.WriteInt64(time(nullptr));
206 parcel.WriteString(session->GetPortName().c_str());
207 parcel.WriteString(session->GetDestination().c_str());
208 parcel.WriteBool(session->GetDelegatePort() == port);
209 parcel.WriteInt32(port);
210 parcel.WriteBool(is_read);
211 parcel.WriteInt32(seq);
212 parcel.WriteInt32(size);
213 parcel.Write(static_cast<const unsigned char*>(buf), size);
215 queue_.Push(std::make_shared<tizen_base::Parcel>(parcel));
219 void DebugPortImpl::Init() {
223 std::lock_guard<std::recursive_mutex> lock(GetMutex());
224 aul_app_com_create_async(ENDPOINT_RPC_PORT_DEBUG, nullptr, AppComCb, this,
226 if (conn_ == nullptr)
234 port_.reset(new Port(fd, "Debug"));
238 SetConnectionStatus(true);
246 int DebugPortImpl::Connect() {
247 if (access(PATH_RPC_PORT_UTIL_SOCK, F_OK) != 0)
250 int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
252 _E("socket() is failed. errno(%d)", errno);
256 struct sockaddr_un addr = { 0, };
257 addr.sun_family = AF_UNIX;
258 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_RPC_PORT_UTIL_SOCK);
260 int ret = connect(fd, reinterpret_cast<struct sockaddr*>(&addr),
263 _E("connect() is failed. fd(%d), errno(%d)", fd, errno);
271 int DebugPortImpl::Watch(int fd) {
272 GIOChannel* io = g_io_channel_unix_new(fd);
274 _E("g_io_channel_unix_new() is failed");
278 GIOCondition cond = static_cast<GIOCondition>(
279 (G_IO_ERR | G_IO_HUP | G_IO_NVAL));
280 guint tag = g_io_add_watch(io, cond, OnDebugPortDisconnectedCb, this);
282 _E("g_io_add_watch() is failed");
283 g_io_channel_unref(io);
292 void DebugPortImpl::Unwatch() {
294 g_io_channel_unref(io_);
299 g_source_remove(watch_tag_);
304 gboolean DebugPortImpl::OnDebugPortDisconnectedCb(GIOChannel* io,
305 GIOCondition cond, gpointer data) {
306 _W("cond(%d)", static_cast<int>(cond));
307 auto* debug_port = static_cast<DebugPortImpl*>(data);
308 std::lock_guard<std::recursive_mutex> lock(debug_port->GetMutex());
309 debug_port->SetConnectionStatus(false);
310 debug_port->watch_tag_ = 0;
311 debug_port->Unwatch();
312 debug_port->port_.reset();
314 return G_SOURCE_REMOVE;
317 void DebugPortImpl::SetConnectionStatus(bool status) {
318 connected_.exchange(status);
321 void DebugPortImpl::CreateThread() {
325 thread_ = std::thread([&]() {
328 std::shared_ptr<tizen_base::Parcel> parcel;
329 queue_.WaitAndPop(parcel);
330 int len = parcel->GetRaw().size();
339 int ret = port_->Write(reinterpret_cast<void*>(&len), sizeof(len));
341 _E("Failed to write size");
342 SetConnectionStatus(false);
346 ret = port_->Write(&*parcel->GetRaw().cbegin(), len);
348 _E("Failed to write data");
349 SetConnectionStatus(false);
358 void DebugPortImpl::JoinThread() {
360 queue_.Push(std::shared_ptr<tizen_base::Parcel>(new tizen_base::Parcel()));
362 if (thread_.joinable()) {
369 std::recursive_mutex& DebugPortImpl::GetMutex() const {
373 int DebugPortImpl::AppComCb(const char* endpoint, aul_app_com_result_e result,
374 bundle* envelope, void* user_data) {
375 const char* val = bundle_get_val(envelope, KEY_PORT_NAME);
379 auto* handle = static_cast<DebugPortImpl*>(user_data);
380 std::string port_name(val);
381 if (port_name.empty() || handle->FindSession(port_name) != nullptr) {
382 auto* handle = static_cast<DebugPortImpl*>(user_data);
383 int fd = handle->Connect();
387 std::lock_guard<std::recursive_mutex> lock(handle->GetMutex());
388 handle->port_.reset(new Port(fd, "Debug"));
389 int ret = handle->Watch(fd);
393 handle->SetConnectionStatus(true);
395 handle->CreateThread();
405 bool DebugPort::IsConnected() {
407 return impl.IsConnected();
410 void DebugPort::AddSession(std::string port_name, std::string destination,
411 int main_port, int delegate_port) {
413 return impl.AddSession(std::move(port_name), std::move(destination),
414 main_port, delegate_port);
417 void DebugPort::RemoveSession(int port) {
419 return impl.RemoveSession(port);
422 int DebugPort::Send(int port, bool is_read, uint32_t seq, const void* buf,
425 return impl.Send(port, is_read, seq, buf, size);
428 } // namespace internal
429 } // namespace rpc_port