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 Stub::Stub(std::string port_name) : port_name_(std::move(port_name)) {
95 std::lock_guard<std::recursive_mutex> lock(GetMutex());
97 for (auto& p : ports_) {
99 DebugPort::RemoveSession(p->GetFd());
106 int Stub::Listen(IEventListener* ev, int fd) {
108 return RPC_PORT_ERROR_INVALID_PARAMETER;
110 if (listener_ != nullptr) {
111 _E("Already listening!");
112 return RPC_PORT_ERROR_INVALID_PARAMETER;
115 std::lock_guard<std::recursive_mutex> lock(GetMutex());
117 server_.reset(new Server(fd, this));
118 return server_->Listen();
121 void Stub::Ignore() {
122 std::lock_guard<std::recursive_mutex> lock(GetMutex());
126 void Stub::AddPrivilege(const std::string& privilege) {
127 std::lock_guard<std::recursive_mutex> lock(GetMutex());
128 access_controller_.AddPrivilege(privilege);
131 void Stub::SetTrusted(const bool trusted) {
132 std::lock_guard<std::recursive_mutex> lock(GetMutex());
133 access_controller_.SetTrusted(trusted);
136 std::shared_ptr<Port> Stub::FindPort(const std::string& instance) const {
137 std::lock_guard<std::recursive_mutex> lock(GetMutex());
138 for (auto& p : ports_) {
139 if (p->GetInstance() == instance && !p->IsDelegate()) {
147 std::shared_ptr<Port> Stub::FindDelegatePort(
148 const std::string& instance) const {
149 std::lock_guard<std::recursive_mutex> lock(GetMutex());
150 for (auto& p : ports_) {
151 if (p->GetInstance() == instance && p->IsDelegate()) {
159 const std::string& Stub::GetPortName() const {
163 void Stub::RemoveAcceptedPorts(std::string instance) {
164 std::lock_guard<std::recursive_mutex> lock(GetMutex());
165 auto iter = ports_.begin();
166 while (iter != ports_.end()) {
167 if ((*iter)->GetInstance().compare(instance) == 0) {
168 LOGI("Close: fd(%d)", (*iter)->GetFd());
169 DebugPort::RemoveSession((*iter)->GetFd());
170 iter = ports_.erase(iter);
177 gboolean Stub::AcceptedPort::OnDataReceived(GIOChannel* channel,
178 GIOCondition cond, gpointer user_data) {
179 auto* stub = static_cast<Stub*>(user_data);
180 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
181 auto* listener = stub->listener_;
182 if (listener == nullptr) {
183 _E("Invalid context");
184 return G_SOURCE_REMOVE;
187 int fd = g_io_channel_unix_get_fd(channel);
188 for (auto& p : stub->ports_) {
189 if (p->GetFd() == fd && !p->IsDelegate()) {
191 if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
192 _W("Socket was disconnected from proxy. fd(%d)", fd);
193 listener->OnDisconnected(p->GetId(), p->GetInstance());
194 stub->RemoveAcceptedPorts(p->GetInstance());
195 Aul::NotifyRpcFinished();
196 return G_SOURCE_CONTINUE;
199 int ret = stub->listener_->OnReceived(p->GetId(), p->GetInstance(),
202 _W("Invalid protocol");
203 listener->OnDisconnected(p->GetId(), p->GetInstance());
204 stub->RemoveAcceptedPorts(p->GetInstance());
205 Aul::NotifyRpcFinished();
206 return G_SOURCE_CONTINUE;
213 return G_SOURCE_CONTINUE;
216 gboolean Stub::AcceptedPort::OnSocketDisconnected(GIOChannel* channel,
217 GIOCondition cond, gpointer user_data) {
218 auto* stub = static_cast<Stub*>(user_data);
219 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
220 auto* listener = stub->listener_;
221 if (listener == nullptr) {
222 _E("Invalid context");
223 return G_SOURCE_REMOVE;
226 int fd = g_io_channel_unix_get_fd(channel);
227 _W("Socket was disconnected. fd(%d)", fd);
228 for (auto& p : stub->ports_) {
229 if (p->GetFd() == fd) {
230 listener->OnDisconnected(p->GetId(), p->GetInstance());
231 stub->RemoveAcceptedPorts(p->GetInstance());
232 Aul::NotifyRpcFinished();
237 return G_SOURCE_REMOVE;
240 void Stub::AddAcceptedPort(const std::string& sender_appid,
241 const std::string& instance, const std::string& port_type, int fd) {
242 std::lock_guard<std::recursive_mutex> lock(GetMutex());
243 if (port_type == kPortTypeMain) {
244 auto* main_port = new AcceptedPort(this, false, fd, sender_appid,
246 ports_.emplace_back(main_port);
250 auto* delegate_port = new AcceptedPort(this, true, fd, sender_appid,
252 ports_.emplace_back(delegate_port);
255 for (auto& p : ports_) {
256 if (p->GetId() == delegate_port->GetId() &&
257 p->GetInstance() == delegate_port->GetInstance() &&
258 p->GetFd() != delegate_port->GetFd()) {
259 main_fd = p->GetFd();
264 _W("sender_appid(%s), instance(%s), main_fd(%d), delegate_fd(%d)",
265 sender_appid.c_str(), instance.c_str(), main_fd, fd);
266 DebugPort::AddSession(port_name_, sender_appid, main_fd, fd);
267 listener_->OnConnected(sender_appid, instance);
270 std::recursive_mutex& Stub::GetMutex() const {
274 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
275 std::string id, std::string inst, bool watch)
276 : Port(fd, std::move(id), std::move(inst)), parent_(parent),
277 is_delegate_(isDelegate) {
281 Stub::AcceptedPort::AcceptedPort(Stub* parent, bool isDelegate, int fd,
282 std::string id, bool watch)
283 : Port(fd, std::move(id)), parent_(parent),
284 is_delegate_(isDelegate) {
288 Stub::AcceptedPort::~AcceptedPort() {
289 if (disconn_source_ > 0)
290 g_source_remove(disconn_source_);
293 g_source_remove(source_);
295 if (channel_ != nullptr)
296 g_io_channel_unref(channel_);
299 int Stub::AcceptedPort::Watch(bool receive) {
300 channel_ = g_io_channel_unix_new(GetFd());
301 if (channel_ == nullptr) {
302 _E("g_io_channel_unix_new() is failed");
306 disconn_source_ = g_io_add_watch(channel_,
307 static_cast<GIOCondition>(G_IO_ERR | G_IO_HUP | G_IO_NVAL),
308 OnSocketDisconnected, parent_);
309 if (disconn_source_ == 0) {
310 _E("g_io_add_watch() is failed");
317 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
318 OnDataReceived, parent_);
320 _E("g_io_add_watch() is failed");
327 Stub::Server::Server(int fd, Stub* parent)
332 Stub::Server::~Server() {
334 g_io_channel_unref(channel_);
337 g_source_remove(source_);
340 int Stub::Server::Listen() {
341 channel_ = g_io_channel_unix_new(GetFd());
342 if (channel_ == nullptr) {
343 _E("g_io_channel_unix_new() is failed");
347 source_ = g_io_add_watch(channel_, static_cast<GIOCondition>(G_IO_IN),
348 OnRequestReceived, parent_);
350 _E("g_io_add_watch() is failed");
357 gboolean Stub::Server::OnRequestReceived(GIOChannel* channel, GIOCondition cond,
358 gpointer user_data) {
359 auto* stub = static_cast<Stub*>(user_data);
360 std::lock_guard<std::recursive_mutex> lock(stub->GetMutex());
361 if (stub->listener_ == nullptr) {
362 _E("Invalid context");
363 return G_SOURCE_REMOVE;
366 std::unique_ptr<ClientSocket> client(stub->server_->Accept());
367 if (client.get() == nullptr) {
369 return G_SOURCE_CONTINUE;
372 Request* request = nullptr;
373 int ret = ReceiveRequest(client.get(), &request);
375 return G_SOURCE_CONTINUE;
377 std::unique_ptr<Request> request_auto(request);
378 std::unique_ptr<PeerCred> cred(PeerCred::Get(client->GetFd()));
379 if (cred.get() == nullptr) {
380 _E("Failed to create peer credentials");
381 return G_SOURCE_CONTINUE;
384 std::string app_id = Aul::GetAppId(cred->GetPid());
386 if (cred->GetUid() >= kRegularUidMin) {
387 if (cred->GetUid() != getuid() && getuid() >= kRegularUidMin) {
388 _E("Reject request. %u:%u", cred->GetUid(), getuid());
391 res = stub->access_controller_.Check(client->GetFd(), app_id);
394 _W("Bypass access control. pid(%d), uid(%u)",
395 cred->GetPid(), cred->GetUid());
399 Response response(res);
400 ret = SendResponse(client.get(), response);
402 return G_SOURCE_CONTINUE;
405 _E("Access denied. fd(%d), pid(%d)", client->GetFd(), cred->GetPid());
406 return G_SOURCE_CONTINUE;
409 client->SetNonblock();
410 int client_fd = client->RemoveFd();
411 stub->AddAcceptedPort(app_id, request->GetInstance(), request->GetPortType(),
413 return G_SOURCE_CONTINUE;
416 } // namespace internal
417 } // namespace rpc_port