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

Commit f6f800ef authored by David Pursell's avatar David Pursell Committed by Gerrit Code Review
Browse files

Merge "libcutils/fastboot: improve multi-buffer write."

parents 989daeaf b34e4a06
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ LOCAL_STATIC_LIBRARIES := \
    libdiagnose_usb \
    libbase \
    libcutils \
    libgtest_host \

# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
LOCAL_CFLAGS_linux := -DUSE_F2FS
+56 −14
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ class UdpSocket : public Socket {

    UdpSocket(Type type, cutils_socket_t sock);

    ssize_t Send(const void* data, size_t length) override;
    bool Send(const void* data, size_t length) override;
    bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
    ssize_t Receive(void* data, size_t length, int timeout_ms) override;

  private:
@@ -109,9 +110,20 @@ UdpSocket::UdpSocket(Type type, cutils_socket_t sock) : Socket(sock) {
    }
}

ssize_t UdpSocket::Send(const void* data, size_t length) {
bool UdpSocket::Send(const void* data, size_t length) {
    return TEMP_FAILURE_RETRY(sendto(sock_, reinterpret_cast<const char*>(data), length, 0,
                                     reinterpret_cast<sockaddr*>(addr_.get()), addr_size_));
                                     reinterpret_cast<sockaddr*>(addr_.get()), addr_size_)) ==
           static_cast<ssize_t>(length);
}

bool UdpSocket::Send(std::vector<cutils_socket_buffer_t> buffers) {
    size_t total_length = 0;
    for (const auto& buffer : buffers) {
        total_length += buffer.length;
    }

    return TEMP_FAILURE_RETRY(socket_send_buffers_function_(
                   sock_, buffers.data(), buffers.size())) == static_cast<ssize_t>(total_length);
}

ssize_t UdpSocket::Receive(void* data, size_t length, int timeout_ms) {
@@ -135,7 +147,8 @@ class TcpSocket : public Socket {
  public:
    TcpSocket(cutils_socket_t sock) : Socket(sock) {}

    ssize_t Send(const void* data, size_t length) override;
    bool Send(const void* data, size_t length) override;
    bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
    ssize_t Receive(void* data, size_t length, int timeout_ms) override;

    std::unique_ptr<Socket> Accept() override;
@@ -144,23 +157,52 @@ class TcpSocket : public Socket {
    DISALLOW_COPY_AND_ASSIGN(TcpSocket);
};

ssize_t TcpSocket::Send(const void* data, size_t length) {
    size_t total = 0;
bool TcpSocket::Send(const void* data, size_t length) {
    while (length > 0) {
        ssize_t sent =
                TEMP_FAILURE_RETRY(send(sock_, reinterpret_cast<const char*>(data), length, 0));

    while (total < length) {
        ssize_t bytes = TEMP_FAILURE_RETRY(
                send(sock_, reinterpret_cast<const char*>(data) + total, length - total, 0));
        if (sent == -1) {
            return false;
        }
        length -= sent;
    }

        if (bytes == -1) {
            if (total == 0) {
                return -1;
    return true;
}

bool TcpSocket::Send(std::vector<cutils_socket_buffer_t> buffers) {
    while (!buffers.empty()) {
        ssize_t sent = TEMP_FAILURE_RETRY(
                socket_send_buffers_function_(sock_, buffers.data(), buffers.size()));

        if (sent == -1) {
            return false;
        }

        // Adjust the buffers to skip past the bytes we've just sent.
        auto iter = buffers.begin();
        while (sent > 0) {
            if (iter->length > static_cast<size_t>(sent)) {
                // Incomplete buffer write; adjust the buffer to point to the next byte to send.
                iter->length -= sent;
                iter->data = reinterpret_cast<const char*>(iter->data) + sent;
                break;
            }
        total += bytes;

            // Complete buffer write; move on to the next buffer.
            sent -= iter->length;
            ++iter;
        }

    return total;
        // Shortcut the common case: we've written everything remaining.
        if (iter == buffers.end()) {
            break;
        }
        buffers.erase(buffers.begin(), iter);
    }

    return true;
}

ssize_t TcpSocket::Receive(void* data, size_t length, int timeout_ms) {
+23 −2
Original line number Diff line number Diff line
@@ -33,11 +33,15 @@
#ifndef SOCKET_H_
#define SOCKET_H_

#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <android-base/macros.h>
#include <cutils/sockets.h>
#include <gtest/gtest_prod.h>

// Socket interface to be implemented for each platform.
class Socket {
@@ -64,8 +68,17 @@ class Socket {
    virtual ~Socket();

    // Sends |length| bytes of |data|. For TCP sockets this will continue trying to send until all
    // bytes are transmitted. Returns the number of bytes actually sent or -1 on error.
    virtual ssize_t Send(const void* data, size_t length) = 0;
    // bytes are transmitted. Returns true on success.
    virtual bool Send(const void* data, size_t length) = 0;

    // Sends |buffers| using multi-buffer write, which can be significantly faster than making
    // multiple calls. For UDP sockets |buffers| are all combined into a single datagram; for
    // TCP sockets this will continue sending until all buffers are fully transmitted. Returns true
    // on success.
    //
    // Note: This is non-functional for UDP server Sockets because it's not currently needed and
    // would require an additional sendto() variation of multi-buffer write.
    virtual bool Send(std::vector<cutils_socket_buffer_t> buffers) = 0;

    // Waits up to |timeout_ms| to receive up to |length| bytes of data. |timout_ms| of 0 will
    // block forever. Returns the number of bytes received or -1 on error/timeout. On timeout
@@ -94,9 +107,17 @@ class Socket {

    cutils_socket_t sock_ = INVALID_SOCKET;

    // Non-class functions we want to override during tests to verify functionality. Implementation
    // should call this rather than using socket_send_buffers() directly.
    std::function<ssize_t(cutils_socket_t, cutils_socket_buffer_t*, size_t)>
            socket_send_buffers_function_ = &socket_send_buffers;

  private:
    int receive_timeout_ms_ = 0;

    FRIEND_TEST(SocketTest, TestTcpSendBuffers);
    FRIEND_TEST(SocketTest, TestUdpSendBuffers);

    DISALLOW_COPY_AND_ASSIGN(Socket);
};

+20 −11
Original line number Diff line number Diff line
@@ -38,26 +38,35 @@ SocketMock::~SocketMock() {
    }
}

ssize_t SocketMock::Send(const void* data, size_t length) {
bool SocketMock::Send(const void* data, size_t length) {
    if (events_.empty()) {
        ADD_FAILURE() << "Send() was called when no message was expected";
        return -1;
        return false;
    }

    if (events_.front().type != EventType::kSend) {
        ADD_FAILURE() << "Send() was called out-of-order";
        return -1;
        return false;
    }

    std::string message(reinterpret_cast<const char*>(data), length);
    if (events_.front().message != message) {
        ADD_FAILURE() << "Send() expected " << events_.front().message << ", but got " << message;
        return -1;
        return false;
    }

    ssize_t return_value = events_.front().return_value;
    events_.pop();
    return return_value;
    return true;
}

// Mock out multi-buffer send to be one large send, since that's what it should looks like from
// the user's perspective.
bool SocketMock::Send(std::vector<cutils_socket_buffer_t> buffers) {
    std::string data;
    for (const auto& buffer : buffers) {
        data.append(reinterpret_cast<const char*>(buffer.data), buffer.length);
    }
    return Send(data.data(), data.size());
}

ssize_t SocketMock::Receive(void* data, size_t length, int /*timeout_ms*/) {
@@ -106,13 +115,13 @@ std::unique_ptr<Socket> SocketMock::Accept() {
}

void SocketMock::ExpectSend(std::string message) {
    ssize_t return_value = message.length();
    events_.push(Event(EventType::kSend, std::move(message), return_value, nullptr));
    events_.push(Event(EventType::kSend, std::move(message), 0, nullptr));
}

void SocketMock::ExpectSendFailure(std::string message) {
    events_.push(Event(EventType::kSend, std::move(message), -1, nullptr));
}
// TODO: make this properly return false to the caller.
//void SocketMock::ExpectSendFailure(std::string message) {
//    events_.push(Event(EventType::kSend, std::move(message), 0, nullptr));
//}

void SocketMock::AddReceive(std::string message) {
    ssize_t return_value = message.length();
+2 −4
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ class SocketMock : public Socket {
    SocketMock();
    ~SocketMock() override;

    ssize_t Send(const void* data, size_t length) override;
    bool Send(const void* data, size_t length) override;
    bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
    ssize_t Receive(void* data, size_t length, int timeout_ms) override;
    int Close() override;
    virtual std::unique_ptr<Socket> Accept();
@@ -64,9 +65,6 @@ class SocketMock : public Socket {
    // Adds an expectation for Send().
    void ExpectSend(std::string message);

    // Adds an expectation for Send() that returns -1.
    void ExpectSendFailure(std::string message);

    // Adds data to provide for Receive().
    void AddReceive(std::string message);

Loading