f386e00c4d7ed7c3acb611fc6c2e2a0a7ba72f9b
[platform/core/appfw/pkgmgr-info.git] / src / common / socket / client_socket.cc
1 /*
2  * Copyright (c) 2021 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 #include "client_socket.hh"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25
26 #include "utils/logging.hh"
27
28 #include "pkgmgrinfo_debug.h"
29
30 namespace {
31
32 bool IsDBWriteRequest(pkgmgr_common::ReqType req_type) {
33   if (req_type != pkgmgr_common::ReqType::SET_PKG_INFO &&
34       req_type != pkgmgr_common::ReqType::SET_CERT_INFO &&
35       req_type != pkgmgr_common::ReqType::WRITE_QUERY)
36     return false;
37
38   return true;
39 }
40
41 }
42
43 namespace pkgmgr_common {
44 namespace socket {
45
46 ClientSocket::ClientSocket(std::string path)
47     : AbstractSocket(std::move(path)) {}
48
49 void ClientSocket::SetTimeout(int timeout_msec) {
50   if (timeout_msec == -1)
51     timeout_msec = 5000;
52
53   if (timeout_msec < 0) {
54     LOG(ERROR) << "Invalid timeout_msec parameter";
55     return;
56   }
57
58   struct timeval timeout = {
59       .tv_sec = static_cast<time_t>(timeout_msec / 1000),
60       .tv_usec = static_cast<suseconds_t>((timeout_msec % 1000) * 1000)};
61
62   if (setsockopt(fd_, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
63     LOG(ERROR) << "setsockopt() is failed. fd: " << fd_
64         << ", errno: " << errno;
65 }
66
67 bool ClientSocket::Connect(ReqType req_type) {
68   if (Create() < 0)
69     return false;
70
71   SetTimeout(IsDBWriteRequest(req_type) ? 60 * 1000 : 5 * 1000);
72
73   int retry_cnt = 3;
74   do {
75     int ret = TryConnection();
76     if (ret == 0) {
77       break;
78     } else if (ret < -1) {
79       LOG(ERROR) << "Maybe peer not launched or peer dead. path: " << GetPath()
80           << ", fd: " << GetFd();
81
82       // If requester is root, don't wait
83       if (getuid() == 0)
84         return false;
85
86       usleep(100 * 1000);
87       --retry_cnt;
88     } else if (ret < 0) {
89       LOG(ERROR) << "Failed to connect to socket: " << GetPath()
90           << ", fd: " << GetFd();
91       return false;
92     }
93   } while (retry_cnt > 0);
94
95   return (retry_cnt > 0);
96 }
97
98 int ClientSocket::TryConnection() {
99   int flags = fcntl(fd_, F_GETFL, 0);
100
101   if (fcntl(fd_, F_SETFL, flags | O_NONBLOCK) != 0) {
102     LOG(ERROR) << "Failed to set flags: " << (flags | O_NONBLOCK) << " on fd: "
103         << fd_ << ", errno: " << errno;
104     return -1;
105   }
106
107   int ret =
108       connect(fd_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_));
109   if (fcntl(fd_, F_SETFL, flags) != 0) {
110     LOG(ERROR) << "Failed to set flags: " << flags << " on fd: " << fd_
111         << ", errno: " <<  errno;
112     return -1;
113   }
114   if (ret < 0) {
115     if (errno != EAGAIN && errno != EINPROGRESS)
116       return -2;
117   } else if (ret == 0) {
118     SetOption();
119     return 0;
120   }
121
122   fd_set readfds;
123   FD_ZERO(&readfds);
124   FD_SET(fd_, &readfds);
125   fd_set writefds = readfds;
126   struct timeval timeout = {0, 100 * 1000};
127   ret = select(fd_ + 1, &readfds, &writefds, NULL, &timeout);
128   if (ret == 0) {
129     errno = ETIMEDOUT;
130     return -1;
131   }
132
133   if (FD_ISSET(fd_, &readfds) || FD_ISSET(fd_, &writefds)) {
134     int error = 0;
135     socklen_t len = sizeof(error);
136     if (getsockopt(fd_, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
137       return -1;
138   }
139
140   return -1;
141 }
142
143 }  // namespace socket
144 }  // namespace pkgmgr_common