• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
143   status = SendData(socket_.Borrow(), request);
144   if (!status)
145     return status.error_status();
146 
147   ResponseHeader<LocalHandle> response;
148   status = ReceiveData(socket_.Borrow(), &response);
149   if (!status)
150     return status.error_status();
151   else if (response.ret_code < 0 || response.channels.size() != 1)
152     return ErrorStatus(EIO);
153 
154   LocalHandle pollin_event_fd = std::move(response.channels[0].pollin_event_fd);
155   LocalHandle pollhup_event_fd =
156       std::move(response.channels[0].pollhup_event_fd);
157 
158   if (!pollin_event_fd || !pollhup_event_fd) {
159     ALOGE(
160         "ClientChannelFactory::Connect: Required fd was not returned from the "
161         "service: pollin_event_fd=%d pollhup_event_fd=%d",
162         pollin_event_fd.Get(), pollhup_event_fd.Get());
163     return ErrorStatus(EIO);
164   }
165 
166   return ClientChannel::Create(ChannelManager::Get().CreateHandle(
167       std::move(socket_), std::move(pollin_event_fd),
168       std::move(pollhup_event_fd)));
169 }
170 
171 }  // namespace uds
172 }  // namespace pdx
173 }  // namespace android
174