1e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <uds/client_channel_factory.h>
2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <errno.h>
4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <log/log.h>
5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <sys/socket.h>
6e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <sys/un.h>
7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <unistd.h>
8e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
94782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko#include <chrono>
104782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko#include <thread>
114782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko
12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <uds/channel_manager.h>
13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <uds/client_channel.h>
14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <uds/ipc_helper.h>
15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
164782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenkousing std::chrono::duration_cast;
174782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenkousing std::chrono::steady_clock;
184782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko
19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android {
20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace pdx {
21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace uds {
22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
23e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostd::string ClientChannelFactory::GetRootEndpointPath() {
24e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  return "/dev/socket/pdx";
25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
26e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostd::string ClientChannelFactory::GetEndpointPath(
28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    const std::string& endpoint_path) {
29e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  std::string path;
30e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  if (!endpoint_path.empty()) {
31e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    if (endpoint_path.front() == '/')
32e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      path = endpoint_path;
33e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    else
34e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      path = GetRootEndpointPath() + '/' + endpoint_path;
35e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  }
36e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  return path;
37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
38e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
39e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex VakulenkoClientChannelFactory::ClientChannelFactory(const std::string& endpoint_path)
40e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    : endpoint_path_{GetEndpointPath(endpoint_path)} {}
41e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
426eefa42d33bdddc3603211634f98937b00abc532Alex VakulenkoClientChannelFactory::ClientChannelFactory(LocalHandle socket)
436eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    : socket_{std::move(socket)} {}
446eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko
45e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostd::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
46e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    const std::string& endpoint_path) {
47e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  return std::unique_ptr<pdx::ClientChannelFactory>{
48e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko      new ClientChannelFactory{endpoint_path}};
49e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
50e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
516eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenkostd::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(
526eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    LocalHandle socket) {
536eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  return std::unique_ptr<pdx::ClientChannelFactory>{
546eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko      new ClientChannelFactory{std::move(socket)}};
556eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko}
566eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko
57e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex VakulenkoStatus<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
58e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    int64_t timeout_ms) const {
594782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  Status<void> status;
60e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
616eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  bool connected = socket_.IsValid();
626eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  if (!connected) {
63e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko    socket_.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
646eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    LOG_ALWAYS_FATAL_IF(
656eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko        endpoint_path_.empty(),
666eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko        "ClientChannelFactory::Connect: unspecified socket path");
676eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  }
686eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko
696eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  if (!socket_) {
704782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
71e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    return ErrorStatus(errno);
72e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  }
73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
744782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  bool use_timeout = (timeout_ms >= 0);
754782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  auto now = steady_clock::now();
764782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  auto time_end = now + std::chrono::milliseconds{timeout_ms};
774782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko
78c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko  int max_eaccess = 5;  // Max number of times to retry when EACCES returned.
794782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  while (!connected) {
804782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    int64_t timeout = -1;
814782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    if (use_timeout) {
824782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      auto remaining = time_end - now;
834782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
844782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      if (timeout < 0)
854782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        return ErrorStatus(ETIMEDOUT);
864782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    }
876eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    sockaddr_un remote;
886eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    remote.sun_family = AF_UNIX;
896eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
906eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko    remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
914782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
924782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    status = WaitForEndpoint(endpoint_path_, timeout);
934782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    if (!status)
944782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      return ErrorStatus(status.error());
954782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko
964782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
974782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    int ret = RETRY_EINTR(connect(
986eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko        socket_.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
994782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    if (ret == -1) {
1004782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
1014782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko            strerror(errno));
102c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko      // if |max_eaccess| below reaches zero when errno is EACCES, the control
103c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko      // flows into the next "else if" statement and a permanent error is
104c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko      // returned from this function.
105c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko      if (errno == ECONNREFUSED || (errno == EACCES && max_eaccess-- > 0)) {
106c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko        // Connection refused/Permission denied can be the result of connecting
107c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko        // too early (the service socket is created but its access rights are
108c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko        // not set or not being listened to yet).
109c0fd676fa087b38b63d253536c6fc9513a0470c8Alex Vakulenko        ALOGD("ClientChannelFactory: %s, waiting...", strerror(errno));
1104782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        using namespace std::literals::chrono_literals;
1114782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        std::this_thread::sleep_for(100ms);
1124782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      } else if (errno != ENOENT && errno != ENOTDIR) {
1134782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        // ENOENT/ENOTDIR might mean that the socket file/directory containing
1144782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        // it has been just deleted. Try to wait for its creation and do not
1154782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        // return an error immediately.
1164782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        ALOGE(
1174782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko            "ClientChannelFactory::Connect: Failed to initialize connection "
1184782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko            "when connecting: %s",
1194782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko            strerror(errno));
1204782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko        return ErrorStatus(errno);
1214782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      }
1224782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    } else {
1234782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      connected = true;
1246eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko      ALOGD("ClientChannelFactory: Connected successfully to %s...",
1256eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko            remote.sun_path);
126e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      ChannelConnectionInfo<LocalHandle> connection_info;
127e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      status = ReceiveData(socket_.Borrow(), &connection_info);
128e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      if (!status)
129e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko        return status.error_status();
130e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      socket_ = std::move(connection_info.channel_fd);
131e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      if (!socket_) {
132e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko        ALOGE("ClientChannelFactory::Connect: Failed to obtain channel socket");
133e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko        return ErrorStatus(EIO);
134e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko      }
1354782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    }
1364782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko    if (use_timeout)
1374782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko      now = steady_clock::now();
1384782814b340bb55a0fbff9f7b6cfd4d27cffd85aAlex Vakulenko  }  // while (!connected)
139e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
140e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  RequestHeader<BorrowedHandle> request;
141e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
14252ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka
1436eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  status = SendData(socket_.Borrow(), request);
144e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  if (!status)
145e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko    return status.error_status();
14652ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka
147e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  ResponseHeader<LocalHandle> response;
1486eefa42d33bdddc3603211634f98937b00abc532Alex Vakulenko  status = ReceiveData(socket_.Borrow(), &response);
149e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  if (!status)
150e41826ac301b9afad1cbfe59c57e27f2495be968Alex Vakulenko    return status.error_status();
15152ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka  else if (response.ret_code < 0 || response.channels.size() != 1)
15252ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka    return ErrorStatus(EIO);
15352ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka
15452ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka  LocalHandle pollin_event_fd = std::move(response.channels[0].pollin_event_fd);
15552ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka  LocalHandle pollhup_event_fd =
15652ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka      std::move(response.channels[0].pollhup_event_fd);
15752ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka
15852ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka  if (!pollin_event_fd || !pollhup_event_fd) {
15952ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka    ALOGE(
16052ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka        "ClientChannelFactory::Connect: Required fd was not returned from the "
16152ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka        "service: pollin_event_fd=%d pollhup_event_fd=%d",
16252ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka        pollin_event_fd.Get(), pollhup_event_fd.Get());
163e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko    return ErrorStatus(EIO);
16452ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka  }
165e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
166e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko  return ClientChannel::Create(ChannelManager::Get().CreateHandle(
16752ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka      std::move(socket_), std::move(pollin_event_fd),
16852ea25cf06cef250ec73052611b48556b3fce4d5Corey Tabaka      std::move(pollhup_event_fd)));
169e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}
170e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko
171e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace uds
172e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace pdx
173e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}  // namespace android
174