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

Commit b77091c1 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7333400 from 316bdbd6 to sc-release

Change-Id: Ie468da9b494a52200feac221ae2ad5571c428365
parents 3666a491 316bdbd6
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -29,6 +29,16 @@

namespace android {

// Service implementations inherit from BBinder and IBinder, and this is frozen
// in prebuilts.
#ifdef __LP64__
static_assert(sizeof(IBinder) == 24);
static_assert(sizeof(BBinder) == 40);
#else
static_assert(sizeof(IBinder) == 12);
static_assert(sizeof(BBinder) == 20);
#endif

// ---------------------------------------------------------------------------

IBinder::IBinder()
+5 −1
Original line number Diff line number Diff line
@@ -78,7 +78,11 @@ static size_t pad_size(size_t s) {
namespace android {

// many things compile this into prebuilts on the stack
static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
#ifdef __LP64__
static_assert(sizeof(Parcel) == 120);
#else
static_assert(sizeof(Parcel) == 60);
#endif

static std::atomic<size_t> gParcelGlobalAllocCount;
static std::atomic<size_t> gParcelGlobalAllocSize;
+34 −220
Original line number Diff line number Diff line
@@ -18,13 +18,7 @@

#include <binder/RpcConnection.h>

#include <arpa/inet.h>
#include <inttypes.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

#include <string_view>
@@ -33,6 +27,7 @@
#include <binder/Stability.h>
#include <utils/String8.h>

#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"

@@ -40,62 +35,9 @@
extern "C" pid_t gettid();
#endif

#ifdef __BIONIC__
#include <linux/vm_sockets.h>
#endif

namespace android {

using base::borrowed_fd;
using base::unique_fd;
using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;

namespace {
bool checkSockaddrSize(const char* name, size_t actual, size_t expected) {
    if (actual >= expected) return true;
    ALOGW("getSockaddrPort: family is %s but size is %zu < %zu", name, actual, expected);
    return false;
}

// Get the port number of |storage| for certain families. Requires storage->sa_family to be
// set to a known family; otherwise, return nullopt.
std::optional<unsigned int> getSockaddrPort(const sockaddr* storage, socklen_t len) {
    switch (storage->sa_family) {
        case AF_INET: {
            if (!checkSockaddrSize("INET", len, sizeof(sockaddr_in))) return std::nullopt;
            auto inetStorage = reinterpret_cast<const sockaddr_in*>(storage);
            return ntohs(inetStorage->sin_port);
        }
        default: {
            uint16_t family = storage->sa_family;
            ALOGW("Don't know how to infer port for family %" PRIu16, family);
            return std::nullopt;
        }
    }
}

std::optional<unsigned int> getSocketPort(borrowed_fd socketfd,
                                          const RpcConnection::SocketAddress& socketAddress) {
    sockaddr_storage storage{};
    socklen_t len = sizeof(storage);
    auto storagePtr = reinterpret_cast<sockaddr*>(&storage);
    if (0 != getsockname(socketfd.get(), storagePtr, &len)) {
        int savedErrno = errno;
        ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
              strerror(savedErrno));
        return std::nullopt;
    }

    // getsockname does not fill in family, but getSockaddrPort() needs it.
    if (storage.ss_family == AF_UNSPEC) {
        storage.ss_family = socketAddress.addr()->sa_family;
    }
    return getSockaddrPort(storagePtr, len);
}

} // namespace

RpcConnection::SocketAddress::~SocketAddress() {}

RpcConnection::RpcConnection() {
    LOG_RPC_DETAIL("RpcConnection created %p", this);
@@ -114,134 +56,20 @@ sp<RpcConnection> RpcConnection::make() {
    return sp<RpcConnection>::make();
}

class UnixSocketAddress : public RpcConnection::SocketAddress {
public:
    explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
        unsigned int pathLen = strlen(path) + 1;
        LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
                            pathLen, path);
        memcpy(mAddr.sun_path, path, pathLen);
    }
    virtual ~UnixSocketAddress() {}
    std::string toString() const override {
        return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
                               mAddr.sun_path)
                .c_str();
    }
    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
    size_t addrSize() const override { return sizeof(mAddr); }

private:
    sockaddr_un mAddr;
};

bool RpcConnection::setupUnixDomainServer(const char* path) {
    return setupSocketServer(UnixSocketAddress(path));
}

bool RpcConnection::setupUnixDomainClient(const char* path) {
    return setupSocketClient(UnixSocketAddress(path));
}

#ifdef __BIONIC__

class VsockSocketAddress : public RpcConnection::SocketAddress {
public:
    VsockSocketAddress(unsigned int cid, unsigned int port)
          : mAddr({
                    .svm_family = AF_VSOCK,
                    .svm_port = port,
                    .svm_cid = cid,
            }) {}
    virtual ~VsockSocketAddress() {}
    std::string toString() const override {
        return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
    }
    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
    size_t addrSize() const override { return sizeof(mAddr); }

private:
    sockaddr_vm mAddr;
};

bool RpcConnection::setupVsockServer(unsigned int port) {
    // realizing value w/ this type at compile time to avoid ubsan abort
    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;

    return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}

bool RpcConnection::setupVsockClient(unsigned int cid, unsigned int port) {
    return setupSocketClient(VsockSocketAddress(cid, port));
}

#endif // __BIONIC__

class InetSocketAddress : public RpcConnection::SocketAddress {
public:
    InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
          : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
    [[nodiscard]] std::string toString() const override {
        return String8::format("%s:%u", mAddr, mPort).c_str();
    }
    [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
    [[nodiscard]] size_t addrSize() const override { return mSize; }

private:
    const sockaddr* mSockAddr;
    size_t mSize;
    const char* mAddr;
    unsigned int mPort;
};

AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
    addrinfo hint{
            .ai_flags = 0,
            .ai_family = AF_UNSPEC,
            .ai_socktype = SOCK_STREAM,
            .ai_protocol = 0,
    };
    addrinfo* aiStart = nullptr;
    if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
        ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
        return AddrInfo(nullptr, nullptr);
    }
    if (aiStart == nullptr) {
        ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
        return AddrInfo(nullptr, nullptr);
    }
    return AddrInfo(aiStart, &freeaddrinfo);
}

bool RpcConnection::setupInetServer(unsigned int port, unsigned int* assignedPort) {
    const char* kAddr = "127.0.0.1";

    if (assignedPort != nullptr) *assignedPort = 0;
    auto aiStart = GetAddrInfo(kAddr, port);
    if (aiStart == nullptr) return false;
    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
        if (!setupSocketServer(socketAddress)) {
            continue;
        }
        auto realPort = getSocketPort(mServer.get(), socketAddress);
        LOG_ALWAYS_FATAL_IF(!realPort.has_value(), "Unable to get port number after setting up %s",
                            socketAddress.toString().c_str());
        LOG_ALWAYS_FATAL_IF(port != 0 && *realPort != port,
                            "Requesting inet server on %s but it is set up on %u.",
                            socketAddress.toString().c_str(), *realPort);
        if (assignedPort != nullptr) {
            *assignedPort = *realPort;
        }
        return true;
    }
    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
          port);
    return false;
}

bool RpcConnection::setupInetClient(const char* addr, unsigned int port) {
    auto aiStart = GetAddrInfo(addr, port);
    auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
    if (aiStart == nullptr) return false;
    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
@@ -287,23 +115,28 @@ status_t RpcConnection::sendDecStrong(const RpcAddress& address) {
    return state()->sendDecStrong(socket.fd(), address);
}

void RpcConnection::join() {
    // TODO(b/185167543): do this dynamically, instead of from a static number
    // of threads
    unique_fd clientFd(
            TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
    if (clientFd < 0) {
        // If this log becomes confusing, should save more state from setupUnixDomainServer
        // in order to output here.
        ALOGE("Could not accept4 socket: %s", strerror(errno));
        return;
status_t RpcConnection::readId() {
    {
        std::lock_guard<std::mutex> _l(mSocketMutex);
        LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
    }

    LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
    int32_t id;

    ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
    status_t status =
            state()->getConnectionId(socket.fd(), sp<RpcConnection>::fromExisting(this), &id);
    if (status != OK) return status;

    LOG_RPC_DETAIL("RpcConnection %p has id %d", this, id);
    mId = id;
    return OK;
}

void RpcConnection::join(unique_fd client) {
    // must be registered to allow arbitrary client code executing commands to
    // be able to do nested calls (we can't only read from it)
    sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd));
    sp<ConnectionSocket> socket = assignServerToThisThread(std::move(client));

    while (true) {
        status_t error =
@@ -319,41 +152,11 @@ void RpcConnection::join() {
                        "bad state: socket object guaranteed to be in list");
}

void RpcConnection::setForServer(const wp<RpcServer>& server) {
    mForServer = server;
}

wp<RpcServer> RpcConnection::server() {
    return mForServer;
}

bool RpcConnection::setupSocketServer(const SocketAddress& addr) {
    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");

    unique_fd serverFd(
            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
    if (serverFd == -1) {
        ALOGE("Could not create socket: %s", strerror(errno));
        return false;
    }

    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
        int savedErrno = errno;
        ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
        return false;
    }

    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
        int savedErrno = errno;
        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
        return false;
    }

    mServer = std::move(serverFd);
    return true;
}

bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
bool RpcConnection::setupSocketClient(const RpcSocketAddress& addr) {
    {
        std::lock_guard<std::mutex> _l(mSocketMutex);
        LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
@@ -373,6 +176,12 @@ bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
        return false;
    }

    if (status_t status = readId(); status != OK) {
        ALOGE("Could not get connection id after initial connection to %s; %s",
              addr.toString().c_str(), statusToString(status).c_str());
        return false;
    }

    // we've already setup one client
    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
        // TODO(b/185167543): avoid race w/ accept4 not being called on server
@@ -385,7 +194,7 @@ bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
    return true;
}

bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr) {
    unique_fd serverFd(
            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
    if (serverFd == -1) {
@@ -406,14 +215,19 @@ bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
    return true;
}

void RpcConnection::addClient(unique_fd&& fd) {
void RpcConnection::addClient(unique_fd fd) {
    std::lock_guard<std::mutex> _l(mSocketMutex);
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    connection->fd = std::move(fd);
    mClients.push_back(connection);
}

sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
void RpcConnection::setForServer(const wp<RpcServer>& server, int32_t connectionId) {
    mId = connectionId;
    mForServer = server;
}

sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd fd) {
    std::lock_guard<std::mutex> _l(mSocketMutex);
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    connection->fd = std::move(fd);
+115 −22
Original line number Diff line number Diff line
@@ -27,10 +27,13 @@
#include <log/log.h>
#include "RpcState.h"

#include "RpcSocketAddress.h"
#include "RpcWireFormat.h"

namespace android {

using base::unique_fd;

RpcServer::RpcServer() {}
RpcServer::~RpcServer() {}

@@ -42,14 +45,63 @@ void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction()
    mAgreedExperimental = true;
}

bool RpcServer::setupUnixDomainServer(const char* path) {
    return setupSocketServer(UnixSocketAddress(path));
}

#ifdef __BIONIC__

bool RpcServer::setupVsockServer(unsigned int port) {
    // realizing value w/ this type at compile time to avoid ubsan abort
    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;

    return setupSocketServer(VsockSocketAddress(kAnyCid, port));
}

#endif // __BIONIC__

bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
    const char* kAddr = "127.0.0.1";

    if (assignedPort != nullptr) *assignedPort = 0;
    auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
    if (aiStart == nullptr) return false;
    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
        if (!setupSocketServer(socketAddress)) {
            continue;
        }

        LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet");
        sockaddr_in addr{};
        socklen_t len = sizeof(addr);
        if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) {
            int savedErrno = errno;
            ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
                  strerror(savedErrno));
            return false;
        }
        LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
                            static_cast<size_t>(len), sizeof(addr));
        unsigned int realPort = ntohs(addr.sin_port);
        LOG_ALWAYS_FATAL_IF(port != 0 && realPort != port,
                            "Requesting inet server on %s but it is set up on %u.",
                            socketAddress.toString().c_str(), realPort);

        if (assignedPort != nullptr) {
            *assignedPort = realPort;
        }

        return true;
    }
    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
          port);
    return false;
}

void RpcServer::setMaxThreads(size_t threads) {
    LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads");
    {
        // this lock should only ever be needed in the error case
        std::lock_guard<std::mutex> _l(mLock);
        LOG_ALWAYS_FATAL_IF(mConnections.size() > 0,
                            "Must specify max threads before creating a connection");
    }
    LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started");
    mMaxThreads = threads;
}

@@ -67,29 +119,35 @@ sp<IBinder> RpcServer::getRootObject() {
    return mRootObject;
}

sp<RpcConnection> RpcServer::addClientConnection() {
void RpcServer::join() {
    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");

    auto connection = RpcConnection::make();
    connection->setForServer(sp<RpcServer>::fromExisting(this));
    {
        std::lock_guard<std::mutex> _l(mLock);
        LOG_ALWAYS_FATAL_IF(mStarted,
                            "currently only supports adding client connections at creation time");
        mConnections.push_back(connection);
    }
    return connection;
}

void RpcServer::join() {
    std::vector<std::thread> pool;
    {
        std::lock_guard<std::mutex> _l(mLock);
        LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
        // TODO(b/185167543): support more than one client at once
        mConnection = RpcConnection::make();
        mConnection->setForServer(sp<RpcServer>::fromExisting(this), 42 /*placeholder id*/);

        mStarted = true;
        for (const sp<RpcConnection>& connection : mConnections) {
            for (size_t i = 0; i < mMaxThreads; i++) {
                pool.push_back(std::thread([=] { connection->join(); }));
                pool.push_back(std::thread([=] {
                    // TODO(b/185167543): do this dynamically, instead of from a static number
                    // of threads
                    unique_fd clientFd(TEMP_FAILURE_RETRY(
                            accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
                    if (clientFd < 0) {
                        // If this log becomes confusing, should save more state from
                        // setupUnixDomainServer in order to output here.
                        ALOGE("Could not accept4 socket: %s", strerror(errno));
                        return;
                    }

                    LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());

                    mConnection->join(std::move(clientFd));
                }));
            }
    }

@@ -98,4 +156,39 @@ void RpcServer::join() {
    for (auto& t : pool) t.join();
}

std::vector<sp<RpcConnection>> RpcServer::listConnections() {
    std::lock_guard<std::mutex> _l(mLock);
    if (mConnection == nullptr) return {};
    return {mConnection};
}

bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
    {
        std::lock_guard<std::mutex> _l(mLock);
        LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
    }

    unique_fd serverFd(
            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
    if (serverFd == -1) {
        ALOGE("Could not create socket: %s", strerror(errno));
        return false;
    }

    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
        int savedErrno = errno;
        ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
        return false;
    }

    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
        int savedErrno = errno;
        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
        return false;
    }

    mServer = std::move(serverFd);
    return true;
}

} // namespace android
+122 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#include <string>

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#ifdef __BIONIC__
#include <linux/vm_sockets.h>
#endif

namespace android {

class RpcSocketAddress {
public:
    virtual ~RpcSocketAddress() {}
    virtual std::string toString() const = 0;
    virtual const sockaddr* addr() const = 0;
    virtual size_t addrSize() const = 0;
};

class UnixSocketAddress : public RpcSocketAddress {
public:
    explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
        unsigned int pathLen = strlen(path) + 1;
        LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
                            pathLen, path);
        memcpy(mAddr.sun_path, path, pathLen);
    }
    virtual ~UnixSocketAddress() {}
    std::string toString() const override {
        return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
                               mAddr.sun_path)
                .c_str();
    }
    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
    size_t addrSize() const override { return sizeof(mAddr); }

private:
    sockaddr_un mAddr;
};

#ifdef __BIONIC__

class VsockSocketAddress : public RpcSocketAddress {
public:
    VsockSocketAddress(unsigned int cid, unsigned int port)
          : mAddr({
                    .svm_family = AF_VSOCK,
                    .svm_port = port,
                    .svm_cid = cid,
            }) {}
    virtual ~VsockSocketAddress() {}
    std::string toString() const override {
        return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
    }
    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
    size_t addrSize() const override { return sizeof(mAddr); }

private:
    sockaddr_vm mAddr;
};

#endif // __BIONIC__

class InetSocketAddress : public RpcSocketAddress {
public:
    InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
          : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
    [[nodiscard]] std::string toString() const override {
        return String8::format("%s:%u", mAddr, mPort).c_str();
    }
    [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
    [[nodiscard]] size_t addrSize() const override { return mSize; }

    using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
    static AddrInfo getAddrInfo(const char* addr, unsigned int port) {
        addrinfo hint{
                .ai_flags = 0,
                .ai_family = AF_UNSPEC,
                .ai_socktype = SOCK_STREAM,
                .ai_protocol = 0,
        };
        addrinfo* aiStart = nullptr;
        if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
            ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
            return AddrInfo(nullptr, nullptr);
        }
        if (aiStart == nullptr) {
            ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
            return AddrInfo(nullptr, nullptr);
        }
        return AddrInfo(aiStart, &freeaddrinfo);
    }

private:
    const sockaddr* mSockAddr;
    size_t mSize;
    const char* mAddr;
    unsigned int mPort;
};

} // namespace android
Loading