You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
7.1 KiB
207 lines
7.1 KiB
/* |
|
* Copyright (C) 2016 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. |
|
*/ |
|
|
|
#include "UnixSocket.h" |
|
|
|
#include <gtest/gtest.h> |
|
|
|
#include <string> |
|
#include <thread> |
|
|
|
TEST(UnixSocket, message_buffer_smoke) { |
|
struct Message { |
|
uint32_t len; |
|
uint32_t type; |
|
char data[10]; |
|
} send_msg; |
|
constexpr size_t send_data_size = 1024; |
|
std::vector<char> send_data(send_data_size); |
|
std::vector<char> read_data; |
|
for (size_t i = 0; i < send_data_size; ++i) { |
|
send_data[i] = i & 0xff; |
|
} |
|
UnixSocketMessageBuffer buffer(100); |
|
size_t per_msg_bytes = 0; |
|
size_t send_bytes = 0; |
|
while (true) { |
|
// Send data as much as possible. |
|
while (send_bytes < send_data_size) { |
|
size_t n = std::min(per_msg_bytes, send_data_size - send_bytes); |
|
per_msg_bytes = (per_msg_bytes + 1) % 10; |
|
memcpy(send_msg.data, &send_data[send_bytes], n); |
|
send_msg.len = sizeof(UnixSocketMessage) + n; |
|
send_msg.type = n; |
|
if (!buffer.StoreMessage( |
|
*reinterpret_cast<UnixSocketMessage*>(&send_msg))) { |
|
break; |
|
} |
|
send_bytes += n; |
|
} |
|
if (buffer.Empty()) { |
|
break; |
|
} |
|
// Read one message. |
|
std::vector<char> read_buf; |
|
auto read_func = [&](size_t size) { |
|
while (read_buf.size() < size) { |
|
const char* p; |
|
size_t n = buffer.PeekData(&p); |
|
n = std::min(n, size - read_buf.size()); |
|
read_buf.insert(read_buf.end(), p, p + n); |
|
buffer.CommitData(n); |
|
} |
|
}; |
|
read_func(sizeof(UnixSocketMessage)); |
|
Message* msg = reinterpret_cast<Message*>(read_buf.data()); |
|
size_t aligned_len = Align(msg->len, UnixSocketMessageAlignment); |
|
read_func(aligned_len); |
|
msg = reinterpret_cast<Message*>(read_buf.data()); |
|
ASSERT_EQ(msg->len, msg->type + sizeof(UnixSocketMessage)); |
|
read_data.insert(read_data.end(), msg->data, msg->data + msg->type); |
|
} |
|
ASSERT_EQ(send_data, read_data); |
|
} |
|
|
|
static void ClientToTestUndelayedMessage(const std::string& path, |
|
bool& client_success) { |
|
std::unique_ptr<UnixSocketConnection> client = |
|
UnixSocketConnection::Connect(path, true); |
|
ASSERT_TRUE(client != nullptr); |
|
IOEventLoop loop; |
|
// For each message received from the server, the client replies a msg |
|
// with type + 1. |
|
auto receive_message_callback = [&](const UnixSocketMessage& msg) { |
|
if (msg.len != sizeof(UnixSocketMessage)) { |
|
return false; |
|
} |
|
UnixSocketMessage reply_msg; |
|
reply_msg.len = sizeof(UnixSocketMessage); |
|
reply_msg.type = msg.type + 1; |
|
return client->SendMessage(reply_msg, true); |
|
}; |
|
auto close_connection_callback = [&]() { return loop.ExitLoop(); }; |
|
ASSERT_TRUE(client->PrepareForIO(loop, receive_message_callback, |
|
close_connection_callback)); |
|
ASSERT_TRUE(loop.RunLoop()); |
|
client_success = true; |
|
} |
|
|
|
TEST(UnixSocket, undelayed_message) { |
|
std::string path = "unix_socket_test_" + std::to_string(getpid()); |
|
std::unique_ptr<UnixSocketServer> server = |
|
UnixSocketServer::Create(path, true); |
|
ASSERT_TRUE(server != nullptr); |
|
bool client_success = false; |
|
std::thread thread( |
|
[&]() { ClientToTestUndelayedMessage(path, client_success); }); |
|
std::unique_ptr<UnixSocketConnection> conn = server->AcceptConnection(); |
|
ASSERT_TRUE(conn != nullptr); |
|
IOEventLoop loop; |
|
uint32_t need_reply_type = 1; |
|
// For each message received from the client, the server replies a msg |
|
// with type + 1, and exits when type reaches 10. |
|
auto receive_message_callback = [&](const UnixSocketMessage& msg) { |
|
if (msg.len != sizeof(UnixSocketMessage) || msg.type != need_reply_type) { |
|
return false; |
|
} |
|
if (need_reply_type >= 10) { |
|
return conn->NoMoreMessage(); |
|
} |
|
UnixSocketMessage new_msg; |
|
new_msg.len = sizeof(UnixSocketMessage); |
|
new_msg.type = msg.type + 1; |
|
need_reply_type = msg.type + 2; |
|
return conn->SendMessage(new_msg, true); |
|
}; |
|
auto close_connection_callback = [&]() { return loop.ExitLoop(); }; |
|
ASSERT_TRUE(conn->PrepareForIO(loop, receive_message_callback, |
|
close_connection_callback)); |
|
UnixSocketMessage msg; |
|
msg.len = sizeof(UnixSocketMessage); |
|
msg.type = 0; |
|
ASSERT_TRUE(conn->SendMessage(msg, true)); |
|
ASSERT_TRUE(loop.RunLoop()); |
|
thread.join(); |
|
ASSERT_TRUE(client_success); |
|
} |
|
|
|
static void ClientToTestBufferedMessage(const std::string& path, |
|
bool& client_success) { |
|
std::unique_ptr<UnixSocketConnection> client = |
|
UnixSocketConnection::Connect(path, true); |
|
ASSERT_TRUE(client != nullptr); |
|
IOEventLoop loop; |
|
// The client exits once receiving a message from the server. |
|
auto receive_message_callback = [&](const UnixSocketMessage& msg) { |
|
if (msg.len != sizeof(UnixSocketMessage) || msg.type != 0) { |
|
return false; |
|
} |
|
return client->NoMoreMessage(); |
|
}; |
|
auto close_connection_callback = [&]() { return loop.ExitLoop(); }; |
|
ASSERT_TRUE(client->PrepareForIO(loop, receive_message_callback, |
|
close_connection_callback)); |
|
// The client sends buffered messages until the send buffer is full. |
|
UnixSocketMessage msg; |
|
msg.len = sizeof(UnixSocketMessage); |
|
msg.type = 0; |
|
while (true) { |
|
msg.type++; |
|
if (!client->SendMessage(msg, false)) { |
|
break; |
|
} |
|
} |
|
ASSERT_TRUE(loop.RunLoop()); |
|
client_success = true; |
|
} |
|
|
|
TEST(UnixSocket, buffered_message) { |
|
std::string path = "unix_socket_test_" + std::to_string(getpid()); |
|
std::unique_ptr<UnixSocketServer> server = |
|
UnixSocketServer::Create(path, true); |
|
ASSERT_TRUE(server != nullptr); |
|
bool client_success = false; |
|
std::thread thread( |
|
[&]() { ClientToTestBufferedMessage(path, client_success); }); |
|
std::unique_ptr<UnixSocketConnection> conn = server->AcceptConnection(); |
|
ASSERT_TRUE(conn != nullptr); |
|
IOEventLoop loop; |
|
uint32_t need_reply_type = 1; |
|
auto receive_message_callback = [&](const UnixSocketMessage& msg) { |
|
// The server checks if the type of received message is increased by one |
|
// each time. |
|
if (msg.len != sizeof(UnixSocketMessage) || msg.type != need_reply_type) { |
|
return false; |
|
} |
|
if (need_reply_type == 1) { |
|
// Notify the client to exit. |
|
UnixSocketMessage new_msg; |
|
new_msg.len = sizeof(UnixSocketMessage); |
|
new_msg.type = 0; |
|
if (!conn->SendMessage(new_msg, true)) { |
|
return false; |
|
} |
|
} |
|
need_reply_type++; |
|
return true; |
|
}; |
|
auto close_connection_callback = [&]() { return loop.ExitLoop(); }; |
|
ASSERT_TRUE(conn->PrepareForIO(loop, receive_message_callback, |
|
close_connection_callback)); |
|
ASSERT_TRUE(loop.RunLoop()); |
|
thread.join(); |
|
ASSERT_TRUE(client_success); |
|
}
|
|
|