1 #include <uds/client_channel_factory.h>
2
3 #include <errno.h>
4 #include <log/log.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <unistd.h>
8
9 #include <chrono>
10 #include <thread>
11
12 #include <uds/channel_manager.h>
13 #include <uds/client_channel.h>
14 #include <uds/ipc_helper.h>
15
16 using std::chrono::duration_cast;
17 using std::chrono::steady_clock;
18
19 namespace android {
20 namespace pdx {
21 namespace uds {
22
GetRootEndpointPath()23 std::string ClientChannelFactory::GetRootEndpointPath() {
24 return "/dev/socket/pdx";
25 }
26
GetEndpointPath(const std::string & endpoint_path)27 std::string ClientChannelFactory::GetEndpointPath(
28 const std::string& endpoint_path) {
29 std::string path;
30 if (!endpoint_path.empty()) {
31 if (endpoint_path.front() == '/')
32 path = endpoint_path;
33 else
34 path = GetRootEndpointPath() + '/' + endpoint_path;
35 }
36 return path;
37 }
38
ClientChannelFactory(const std::string & endpoint_path)39 ClientChannelFactory::ClientChannelFactory(const std::string& endpoint_path)
40 : endpoint_path_{GetEndpointPath(endpoint_path)} {}
41
ClientChannelFactory(LocalHandle socket)42 ClientChannelFactory::ClientChannelFactory(LocalHandle socket)
43 : socket_{std::move(socket)} {}
44
Create(const std::string & endpoint_path)45 std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
46 const std::string& endpoint_path) {
47 return std::unique_ptr<pdx::ClientChannelFactory>{
48 new ClientChannelFactory{endpoint_path}};
49 }
50
Create(LocalHandle socket)51 std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
52 LocalHandle socket) {
53 return std::unique_ptr<pdx::ClientChannelFactory>{
54 new ClientChannelFactory{std::move(socket)}};
55 }
56
Connect(int64_t timeout_ms) const57 Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
58 int64_t timeout_ms) const {
59 Status<void> status;
60
61 bool connected = socket_.IsValid();
62 if (!connected) {
63 socket_.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
64 LOG_ALWAYS_FATAL_IF(
65 endpoint_path_.empty(),
66 "ClientChannelFactory::Connect: unspecified socket path");
67 }
68
69 if (!socket_) {
70 ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
71 return ErrorStatus(errno);
72 }
73
74 bool use_timeout = (timeout_ms >= 0);
75 auto now = steady_clock::now();
76 auto time_end = now + std::chrono::milliseconds{timeout_ms};
77
78 int max_eaccess = 5; // Max number of times to retry when EACCES returned.
79 while (!connected) {
80 int64_t timeout = -1;
81 if (use_timeout) {
82 auto remaining = time_end - now;
83 timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
84 if (timeout < 0)
85 return ErrorStatus(ETIMEDOUT);
86 }
87 sockaddr_un remote;
88 remote.sun_family = AF_UNIX;
89 strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
90 remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
91 ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
92 status = WaitForEndpoint(endpoint_path_, timeout);
93 if (!status)
94 return ErrorStatus(status.error());
95
96 ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
97 int ret = RETRY_EINTR(connect(
98 socket_.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
99 if (ret == -1) {
100 ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
101 strerror(errno));
102 // if |max_eaccess| below reaches zero when errno is EACCES, the control
103 // flows into the next "else if" statement and a permanent error is
104 // returned from this function.
105 if (errno == ECONNREFUSED || (errno == EACCES && max_eaccess-- > 0)) {
106 // Connection refused/Permission denied can be the result of connecting
107 // too early (the service socket is created but its access rights are
108 // not set or not being listened to yet).
109 ALOGD("ClientChannelFactory: %s, waiting...", strerror(errno));
110 using namespace std::literals::chrono_literals;
111 std::this_thread::sleep_for(100ms);
112 } else if (errno != ENOENT && errno != ENOTDIR) {
113 // ENOENT/ENOTDIR might mean that the socket file/directory containing
114 // it has been just deleted. Try to wait for its creation and do not
115 // return an error immediately.
116 ALOGE(
117 "ClientChannelFactory::Connect: Failed to initialize connection "
118 "when connecting: %s",
119 strerror(errno));
120 return ErrorStatus(errno);
121 }
122 } else {
123 connected = true;
124 ALOGD("ClientChannelFactory: Connected successfully to %s...",
125 remote.sun_path);
126 ChannelConnectionInfo<LocalHandle> connection_info;
127 status = ReceiveData(socket_.Borrow(), &connection_info);
128 if (!status)
129 return status.error_status();
130 socket_ = std::move(connection_info.channel_fd);
131 if (!socket_) {
132 ALOGE("ClientChannelFactory::Connect: Failed to obtain channel socket");
133 return ErrorStatus(EIO);
134 }
135 }
136 if (use_timeout)
137 now = steady_clock::now();
138 } // while (!connected)
139
140 RequestHeader<BorrowedHandle> request;
141 InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
142 status = SendData(socket_.Borrow(), request);
143 if (!status)
144 return status.error_status();
145 ResponseHeader<LocalHandle> response;
146 status = ReceiveData(socket_.Borrow(), &response);
147 if (!status)
148 return status.error_status();
149 int ref = response.ret_code;
150 if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size())
151 return ErrorStatus(EIO);
152
153 LocalHandle event_fd = std::move(response.file_descriptors[ref]);
154 return ClientChannel::Create(ChannelManager::Get().CreateHandle(
155 std::move(socket_), std::move(event_fd)));
156 }
157
158 } // namespace uds
159 } // namespace pdx
160 } // namespace android
161