2 * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
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 <aul_rpc_port.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
26 #include "aul-internal.hh"
27 #include "debug-port-internal.hh"
28 #include "include/rpc-port.h"
29 #include "log-private.hh"
30 #include "peer-cred-internal.hh"
31 #include "request-internal.hh"
32 #include "response-internal.hh"
33 #include "stub-internal.hh"
39 constexpr const char kPortTypeMain[] = "main";
40 constexpr const char kPortTypeDelegate[] = "delegate";
41 constexpr uid_t kRegularUidMin = 5000;
43 int ReceiveRequest(ClientSocket* client, Request** request) {
45 int ret = client->Receive(reinterpret_cast<void*>(&size), sizeof(size));
47 _E("Receive() is failed. error(%d)", ret);
51 std::vector<uint8_t> buf(size);
52 ret = client->Receive(buf.data(), size);
54 _E("Receive() is failed. error(%d)", ret);
58 tizen_base::Parcel parcel(buf.data(), buf.size());
59 *request = new (std::nothrow) Request();
60 if (*request == nullptr) {
65 parcel.ReadParcelable(*request);
69 int SendResponse(ClientSocket* client, const Response& response) {
70 tizen_base::Parcel parcel;
71 parcel.WriteParcelable(const_cast<Response&>(response));
72 size_t size = parcel.GetDataSize();
73 int ret = client->Send(reinterpret_cast<void*>(&size), sizeof(size));
75 _E("Send() is failed. error(%d)", ret);
79 ret = client->Send(parcel.GetData(), size);
81 _E("Send() is failed. error(%d)", ret);
90 std::unordered_set<Stub*> Stub::freed_stubs_;
92 Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) {
94 freed_stubs_.erase(this);
98 std::lock_guard<std::recursive_mutex> lock(GetMutex());
100 for (auto& p : ports_) {
101 if (!p->IsDelegate())
102 DebugPort::RemoveSession(p->GetFd());
107 freed_stubs_.insert(this);
110 int Stub::Listen(IEventListener* ev, int fd) {
112 return RPC_PORT_ERROR_INVALID_PARAMETER;
114 if (listener_ != nullptr) {
115 _E("Already listening!");
116 return RPC_PORT_ERROR_INVALID_PARAMETER;
119 std::lock_guard<std::recursive_mutex> lock(GetMutex());
121 server_.reset(new Server(fd, this));
122 return server_->Listen();
125 void Stub::Ignore() {
126 std::lock_guard<std::recursive_mutex> lock(GetMutex());
130 void Stub::AddPrivilege(const std::string& privilege) {
131 std::lock_guard<std::recursive_mutex> lock(GetMutex());
132 access_controller_.AddPrivilege(privilege);
135 void Stub::SetTrusted(const bool trusted) {
136 std::lock_guard<std::recursive_mutex> lock(GetMutex());
137 access_controller_.SetTrusted(trusted);
140 std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
141 std::lock_guard<std::recursive_mutex> lock(GetMutex());
142 for (auto& p : ports_) {
143 if (p->GetInstance() == instance && !p->IsDelegate()) {
151 std::shared_ptr<Port> Stub::FindDelegatePort(
152 const std::string& instance) const {
153 std::lock_guard<std::recursive_mutex> lock(GetMutex());
154 for (auto& p : ports_) {
155 if (p->GetInstance() == instance && p->IsDelegate()) {
163 const std::string& Stub::GetPortName() const {
167 void Stub::RemoveAcceptedPorts(std::string instance) {
168 std::lock_guard<std::recursive_mutex> lock(GetMutex());
169 auto iter = ports_.begin();
170 while (iter != ports_.end()) {
171 if ((*iter)->GetInstance().compare(instance) == 0) {
172 LOGI("Close: fd(%d)", (*iter)->GetFd());
173 DebugPort::RemoveSession((*iter)->GetFd());
174 iter = ports_.erase(iter);
181 gboolean Stub::AcceptedPort::OnDataReceived(GIOChannel* channel,
182 GIOCondition cond, gpointer user_data) {
183 auto* stub = static_cast<Stub*>(user_data);
184 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
185 auto* listener = stub->listener_;
186 if (listener == nullptr) {
187 _E("Invalid context");
188 return G_SOURCE_REMOVE;
191 int fd = g_io_channel_unix_get_fd(channel);
192 for (auto& p : stub->ports_) {
193 if (p->GetFd() == fd && !p->IsDelegate()) {
195 if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
196 _W("Socket was disconnected from proxy. fd(%d)", fd);
197 listener->OnDisconnected(p->GetId(), p->GetInstance());
198 stub->RemoveAcceptedPorts(p->GetInstance());
199 Aul::NotifyRpcFinished();
200 return G_SOURCE_CONTINUE;
203 int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(),
206 _W("Invalid protocol");
207 listener->OnDisconnected(p->GetId(), p->GetInstance());
208 stub->RemoveAcceptedPorts(p->GetInstance());
209 Aul::NotifyRpcFinished();
210 return G_SOURCE_CONTINUE;
217 return G_SOURCE_CONTINUE;
220 gboolean Stub::AcceptedPort::OnSocketDisconnected(GIOChannel* channel,
221 GIOCondition cond, gpointer user_data) {
222 auto* stub = static_cast<Stub*>(user_data);
223 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
224 auto* listener = stub->listener_;
225 if (listener == nullptr) {
226 _E("Invalid context");
227 return G_SOURCE_REMOVE;
230 int fd = g_io_channel_unix_get_fd(channel);
231 _W("Socket was disconnected. fd(%d)", fd);
232 for (auto& p : stub->ports_) {
233 if (p->GetFd() == fd) {
234 listener->OnDisconnected(p->GetId(), p->GetInstance());
235 stub->RemoveAcceptedPorts(p->GetInstance());
236 Aul::NotifyRpcFinished();
241 return G_SOURCE_REMOVE;
244 void Stub::AddAcceptedPort(const std::string& sender_appid,
245 const std::string& instance, const std::string& port_type, int fd) {
246 std::lock_guard<std::recursive_mutex> lock(GetMutex());
247 if (port_type == kPortTypeMain) {
248 auto* main_port = new AcceptedPort(this, false, fd, sender_appid,
250 ports_.emplace_back(main_port);
254 auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid,
256 ports_.emplace_back(delegate_port);
259 for (auto& p : ports_) {
260 if (p->GetId() == delegate_port->GetId() &&
261 p->GetInstance() == delegate_port->GetInstance() &&
262 p->GetFd() != delegate_port->GetFd()) {
263 main_fd = p->GetFd();
268 _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)",
269 sender_appid.c_str(), instance.c_str(), main_fd, fd);
270 DebugPort::AddSession(port_name_, sender_appid, main_fd, fd);
271 listener_->OnConnected(sender_appid, instance);
274 std::recursive_mutex& Stub::GetMutex() const {
278 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
279 std::string id, std::string inst, bool watch)
280 : Port(fd, std::move(id), std::move(inst)), parent_(parent),
281 is_delegate_(isDelegate) {
285 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
286 std::string id, bool watch)
287 : Port(fd, std::move(id)), parent_(parent),
288 is_delegate_(isDelegate) {
292 Stub::AcceptedPort::~AcceptedPort() {
293 if (disconn_source_ > 0)
294 g_source_remove(disconn_source_);
297 g_source_remove(source_);
299 if (channel_ != nullptr)
300 g_io_channel_unref(channel_);
303 int Stub::AcceptedPort::Watch(bool receive) {
304 channel_ = g_io_channel_unix_new(GetFd());
305 if (channel_ == nullptr) {
306 _E("g_io_channel_unix_new() is failed");
310 disconn_source_ = g_io_add_watch(channel_,
311 static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
312 OnSocketDisconnected, parent_);
313 if (disconn_source_ == 0) {
314 _E("g_io_add_watch() is failed");
321 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
322 OnDataReceived, parent_);
324 _E("g_io_add_watch() is failed");
331 Stub::Server::Server(int fd, Stub* parent)
336 Stub::Server::~Server() {
338 g_io_channel_unref(channel_);
341 g_source_remove(source_);
344 int Stub::Server::Listen() {
345 channel_ = g_io_channel_unix_new(GetFd());
346 if (channel_ == nullptr) {
347 _E("g_io_channel_unix_new() is failed");
351 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
352 OnRequestReceived, parent_);
354 _E("g_io_add_watch() is failed");
361 gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond,
362 gpointer user_data) {
363 auto* stub = static_cast<Stub*>(user_data);
364 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
365 if (stub->listener_ == nullptr) {
366 _E("Invalid context");
367 return G_SOURCE_REMOVE;
370 std::shared_ptr<ClientSocket> client(stub->server_->Accept());
371 if (client.get() == nullptr) {
373 return G_SOURCE_CONTINUE;
376 Request* request = nullptr;
377 int ret = ReceiveRequest(client.get(), &request);
379 return G_SOURCE_CONTINUE;
381 std::shared_ptr<Request> request_auto(request);
382 std::shared_ptr<PeerCred> cred(PeerCred::Get(client->GetFd()));
383 if (cred.get() == nullptr) {
384 _E("Failed to create peer credentials");
385 return G_SOURCE_CONTINUE;
388 std::string app_id = Aul::GetAppId(cred->GetPid());
389 auto response_func = [=](int res) -> void {
390 if (freed_stubs_.find(stub) != freed_stubs_.end())
393 Response response(res);
394 int ret = SendResponse(client.get(), response);
399 _E("Access denied. fd(%d), pid(%d)", client->GetFd(), cred->GetPid());
403 client->SetNonblock();
404 int client_fd = client->RemoveFd();
405 stub->AddAcceptedPort(app_id, request_auto->GetInstance(),
406 request_auto->GetPortType(), client_fd);
410 if (cred->GetUid() >= kRegularUidMin) {
411 if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) {
412 _E("Reject request. %u:%u", cred->GetUid(), getuid());
415 stub->access_controller_.CheckAsync(client->GetFd(), app_id,
417 return G_SOURCE_CONTINUE;
420 _W("Bypass access control. pid(%d), uid(%u)",
421 cred->GetPid(), cred->GetUid());
426 return G_SOURCE_CONTINUE;
429 } // namespace internal
430 } // namespace rpc_port