Merge "libcutils: add multi-buffer socket send."

am: d95ecfc432

* commit 'd95ecfc432206d5408738bb7cbc6eb15e5827d91':
  libcutils: add multi-buffer socket send.
This commit is contained in:
David Pursell 2016-02-02 19:23:51 +00:00 committed by android-build-merger
commit d56499b21d
4 changed files with 82 additions and 9 deletions

View File

@ -30,12 +30,15 @@
typedef int socklen_t;
typedef SOCKET cutils_socket_t;
typedef WSABUF cutils_socket_buffer_t;
#else
#include <sys/socket.h>
#include <sys/uio.h>
typedef int cutils_socket_t;
typedef struct iovec cutils_socket_buffer_t;
#define INVALID_SOCKET (-1)
#endif
@ -136,6 +139,28 @@ int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms);
*/
int socket_get_local_port(cutils_socket_t sock);
/*
* Sends to a socket from multiple buffers; wraps writev() on Unix or WSASend()
* on Windows. This can give significant speedup compared to calling send()
* multiple times.
*
* Because Unix and Windows use different structs to hold buffers, we also
* need a generic function to set up the buffers.
*
* Example usage:
* cutils_socket_buffer_t buffers[2] = {
* make_cutils_socket_buffer(data0, len0),
* make_cutils_socket_buffer(data1, len1)
* };
* socket_send_buffers(sock, buffers, 2);
*
* Returns the number of bytes written or -1 on error.
*/
cutils_socket_buffer_t make_cutils_socket_buffer(void* data, size_t length);
ssize_t socket_send_buffers(cutils_socket_t sock,
cutils_socket_buffer_t* buffers,
size_t num_buffers);
/*
* socket_peer_is_trusted - Takes a socket which is presumed to be a
* connected local socket (e.g. AF_LOCAL) and returns whether the peer

View File

@ -47,12 +47,25 @@ bool socket_peer_is_trusted(int fd __android_unused)
}
int socket_close(int sock) {
return close(sock);
return close(sock);
}
int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
}
cutils_socket_buffer_t make_cutils_socket_buffer(void* data, size_t length) {
cutils_socket_buffer_t buffer;
buffer.iov_base = data;
buffer.iov_len = length;
return buffer;
}
ssize_t socket_send_buffers(cutils_socket_t sock,
cutils_socket_buffer_t* buffers,
size_t num_buffers) {
return writev(sock, buffers, num_buffers);
}

View File

@ -58,3 +58,22 @@ int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout_ms,
sizeof(timeout_ms));
}
cutils_socket_buffer_t make_cutils_socket_buffer(void* data, size_t length) {
cutils_socket_buffer_t buffer;
buffer.buf = data;
buffer.len = length;
return buffer;
}
ssize_t socket_send_buffers(cutils_socket_t sock,
cutils_socket_buffer_t* buffers,
size_t num_buffers) {
DWORD bytes_sent = 0;
if (WSASend(sock, buffers, num_buffers, &bytes_sent, 0, NULL, NULL) !=
SOCKET_ERROR) {
return bytes_sent;
}
return -1;
}

View File

@ -34,17 +34,17 @@ static void TestConnectedSockets(cutils_socket_t server, cutils_socket_t client,
ASSERT_NE(INVALID_SOCKET, server);
ASSERT_NE(INVALID_SOCKET, client);
char buffer[3];
char buffer[128];
sockaddr_storage addr;
socklen_t addr_size = sizeof(addr);
// Send client -> server first to get the UDP client's address.
ASSERT_EQ(3, send(client, "foo", 3, 0));
if (type == SOCK_DGRAM) {
EXPECT_EQ(3, recvfrom(server, buffer, 3, 0,
EXPECT_EQ(3, recvfrom(server, buffer, sizeof(buffer), 0,
reinterpret_cast<sockaddr*>(&addr), &addr_size));
} else {
EXPECT_EQ(3, recv(server, buffer, 3, 0));
EXPECT_EQ(3, recv(server, buffer, sizeof(buffer), 0));
}
EXPECT_EQ(0, memcmp(buffer, "foo", 3));
@ -55,9 +55,20 @@ static void TestConnectedSockets(cutils_socket_t server, cutils_socket_t client,
} else {
ASSERT_EQ(3, send(server, "bar", 3, 0));
}
EXPECT_EQ(3, recv(client, buffer, 3, 0));
EXPECT_EQ(3, recv(client, buffer, sizeof(buffer), 0));
EXPECT_EQ(0, memcmp(buffer, "bar", 3));
// Send multiple buffers using socket_send_buffers().
std::string data[] = {"foo", "bar", "12345"};
cutils_socket_buffer_t socket_buffers[3];
for (int i = 0; i < 3; ++i) {
socket_buffers[i] = make_cutils_socket_buffer(&data[i][0],
data[i].length());
}
EXPECT_EQ(11, socket_send_buffers(client, socket_buffers, 3));
EXPECT_EQ(11, recv(server, buffer, sizeof(buffer), 0));
EXPECT_EQ(0, memcmp(buffer, "foobar12345", 11));
EXPECT_EQ(0, socket_close(server));
EXPECT_EQ(0, socket_close(client));
}
@ -171,3 +182,8 @@ TEST(SocketsTest, TestTcpReceiveTimeout) {
EXPECT_EQ(0, socket_close(client));
EXPECT_EQ(0, socket_close(handler));
}
// Tests socket_send_buffers() failure.
TEST(SocketsTest, TestSocketSendBuffersFailure) {
EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
}