Remove sqlite dependency from pkgmgr_parser_db (#167)
[platform/core/appfw/pkgmgr-info.git] / src / client / pkginfo_client.cc
1 // Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "pkginfo_client.hh"
6
7 #include <dlfcn.h>
8
9 #include <parcel.hh>
10 #include <vconf.h>
11
12 #include <string>
13
14 #include "parcelable_factory.hh"
15
16 #include "pkgmgrinfo_debug.h"
17 #include "pkgmgrinfo_private.h"
18
19 #define LIBPKGMGR_INFO "/usr/lib/libpkgmgr-info-server.so.0"
20 #define DIRECT_ACCESS_FUNC "_request_handler_direct_access"
21
22 namespace pkgmgr_client {
23
24 constexpr const char SOCK_PATH[] = "/run/pkgmgr-info-server";
25
26 PkgInfoClient::PkgInfoClient(
27     std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable> parcel,
28     uid_t uid, pkgmgr_common::ReqType req_type)
29     : parcel_(parcel),
30       result_parcel_(nullptr),
31       uid_(uid),
32       req_type_(req_type),
33       is_offline_(false) {
34   socket_ = std::make_unique<pkgmgr_common::socket::ClientSocket>(SOCK_PATH);
35 }
36
37 PkgInfoClient::~PkgInfoClient() {
38   if (socket_ != nullptr)
39     socket_->Disconnect();
40 }
41
42 bool PkgInfoClient::SendRequest() {
43   if (socket_ == nullptr) {
44     LOGE("Socket is not ready");
45     return false;
46   }
47
48   // CREATE_DB request type need to be executed directly by the caller
49   if (req_type_ == pkgmgr_common::ReqType::CREATE_DB) {
50     is_offline_ = true;
51     return RequestHandlerDirectAccess();
52   }
53
54   if (!socket_->Connect()) {
55     LOGE("Failed to connect client socket, try to direct access");
56     socket_->Disconnect();
57     is_offline_ = true;
58     return RequestHandlerDirectAccess();
59   }
60
61   if (socket_->SendData(&req_type_, sizeof(req_type_)) != 0) {
62     LOGE("fail to send data");
63     socket_->Disconnect();
64     return false;
65   }
66
67   tizen_base::Parcel p;
68   p.WriteParcelable(*parcel_.get());
69   const auto& raw = p.GetRaw();
70   int len = raw.size();
71
72   if (socket_->SendData(&len, sizeof(len)) != 0) {
73     LOGE("fail to send data");
74     socket_->Disconnect();
75     return false;
76   }
77
78   if (socket_->SendData(&raw[0], len) != 0) {
79     LOGE("Fail to send data");
80     socket_->Disconnect();
81     return false;
82   }
83
84   return true;
85 }
86
87 std::shared_ptr<pkgmgr_common::parcel::AbstractParcelable>
88 PkgInfoClient::GetResultParcel() {
89   if (is_offline_)
90     return result_parcel_;
91
92   if (socket_ == nullptr) {
93     LOGE("Socket is not ready");
94     return nullptr;
95   }
96   int len = 0;
97   if (socket_->ReceiveData(&len, sizeof(len)) != 0 || len <= 0) {
98     LOGE("Fail to receive data");
99     socket_->Disconnect();
100     return nullptr;
101   }
102
103   unsigned char* raw = new (std::nothrow) unsigned char[len];
104   if (raw == nullptr) {
105     LOGE("Out of memory");
106     socket_->Disconnect();
107     return nullptr;
108   }
109
110   if (socket_->ReceiveData(raw, len) != 0) {
111     LOGE("Fail to receive data");
112     socket_->Disconnect();
113     delete[] raw;
114     return nullptr;
115   }
116   socket_->Disconnect();
117
118   auto res = pkgmgr_common::parcel::ParcelableFactory::GetInst().CreateParcel(
119       raw, len);
120   delete[] raw;
121
122   return res;
123 }
124
125 bool PkgInfoClient::RequestHandlerDirectAccess() {
126   tizen_base::Parcel p;
127   p.WriteParcelable(*parcel_.get());
128   std::vector<uint8_t> raw = p.GetRaw();
129   std::unique_ptr<char, decltype(std::free)*> locale(
130       _get_system_locale(), std::free);
131   if (locale.get() == nullptr)
132     return false;
133
134   static void* handle = nullptr;
135   static void* (*dl_func)(int, unsigned char*, int, const char *);
136
137   if (handle == nullptr) {
138     handle = dlopen(LIBPKGMGR_INFO, RTLD_LOCAL | RTLD_LAZY);
139     if (!handle) {
140       LOGE("Failed to open library: %s (%s)", LIBPKGMGR_INFO, dlerror());
141       return false;
142     }
143     dl_func = reinterpret_cast<void* (*)(int, unsigned char*, int, const char *)>(
144         dlsym(handle, DIRECT_ACCESS_FUNC));
145     if (dl_func == nullptr) {
146       LOGE("cannot find %s symbol in (%s)", DIRECT_ACCESS_FUNC, LIBPKGMGR_INFO);
147       dlclose(handle);
148       handle = nullptr;
149       return false;
150     }
151   }
152
153   result_parcel_.reset(
154       reinterpret_cast<pkgmgr_common::parcel::AbstractParcelable *>(
155           dl_func(req_type_, &raw[0], raw.size(), locale.get())));
156
157   return true;
158 }
159
160 }  // namespace pkgmgr_client