Merge "libcutils: add multi-buffer socket send."
am: d95ecfc432
* commit 'd95ecfc432206d5408738bb7cbc6eb15e5827d91':
libcutils: add multi-buffer socket send.
This commit is contained in:
commit
d56499b21d
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue