Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ef31031 authored by Alex Vakulenko's avatar Alex Vakulenko Committed by android-build-merger
Browse files

libpdx_uds: Improve client connection logic

am: 4782814b

Change-Id: I9b1653020b4f619d9761a66886e73a962fc26777
parents e5f5f824 4782814b
Loading
Loading
Loading
Loading
+56 −13
Original line number Diff line number Diff line
@@ -6,10 +6,16 @@
#include <sys/un.h>
#include <unistd.h>

#include <chrono>
#include <thread>

#include <uds/channel_manager.h>
#include <uds/client_channel.h>
#include <uds/ipc_helper.h>

using std::chrono::duration_cast;
using std::chrono::steady_clock;

namespace android {
namespace pdx {
namespace uds {
@@ -41,13 +47,11 @@ std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create(

Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
    int64_t timeout_ms) const {
  auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
  if (!status)
    return ErrorStatus(status.error());
  Status<void> status;

  LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
  if (!socket_fd) {
    ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
    ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
    return ErrorStatus(errno);
  }

@@ -56,16 +60,55 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
  strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
  remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';

  bool use_timeout = (timeout_ms >= 0);
  auto now = steady_clock::now();
  auto time_end = now + std::chrono::milliseconds{timeout_ms};

  bool connected = false;
  while (!connected) {
    int64_t timeout = -1;
    if (use_timeout) {
      auto remaining = time_end - now;
      timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
      if (timeout < 0)
        return ErrorStatus(ETIMEDOUT);
    }
    ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
    status = WaitForEndpoint(endpoint_path_, timeout);
    if (!status)
      return ErrorStatus(status.error());

    ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
    int ret = RETRY_EINTR(connect(
        socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
    if (ret == -1) {
      ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
            strerror(errno));
      if (errno == ECONNREFUSED) {
        // Connection refused can be the result of connecting too early (the
        // service socket is created but not being listened to yet).
        ALOGD("ClientChannelFactory: Connection refused, waiting...");
        using namespace std::literals::chrono_literals;
        std::this_thread::sleep_for(100ms);
      } else if (errno != ENOENT && errno != ENOTDIR) {
        // ENOENT/ENOTDIR might mean that the socket file/directory containing
        // it has been just deleted. Try to wait for its creation and do not
        // return an error immediately.
        ALOGE(
        "ClientChannelFactory::Connect: Failed to initialize connection when "
        "connecting %s",
            "ClientChannelFactory::Connect: Failed to initialize connection "
            "when connecting: %s",
            strerror(errno));
        return ErrorStatus(errno);
      }
    } else {
      connected = true;
    }
    if (use_timeout)
      now = steady_clock::now();
  }  // while (!connected)

  ALOGD("ClientChannelFactory: Connected successfully to %s...",
        remote.sun_path);
  RequestHeader<BorrowedHandle> request;
  InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
  status = SendData(socket_fd.Get(), request);