Verify that IO on closed socket returns an error

The test implementation of BluetoothSocket::GetInputStream() would crash if
the socket was closed. That's not ideal because the caller can't verify if the
socket is open or closed.

New test verifies that GetOutputStream() and GetInputStream() always return a
valid reference.

PiperOrigin-RevId: 518722540
This commit is contained in:
Janusz Sobczak
2023-03-22 18:04:12 -07:00
committed by Copybara-Service
parent 1a78b33a89
commit adcb341190
3 changed files with 63 additions and 2 deletions
@@ -231,6 +231,50 @@ TEST_F(BluetoothClassicMediumTest, SendData) {
server_socket.Close();
}
TEST_F(BluetoothClassicMediumTest, IoOnClosedSocketReturnsError) {
adapter_a_->SetScanMode(BluetoothAdapter::ScanMode::kConnectable);
CountDownLatch found_latch(1);
BluetoothDevice* discovered_device = nullptr;
bt_a_->StartDiscovery(DiscoveryCallback{
.device_discovered_cb =
[this, &found_latch, &discovered_device](BluetoothDevice& device) {
NEARBY_LOG(INFO, "Device discovered: %s", device.GetName().c_str());
EXPECT_EQ(device.GetName(), adapter_b_->GetName());
discovered_device = &device;
found_latch.CountDown();
},
});
adapter_b_->SetScanMode(BluetoothAdapter::ScanMode::kConnectableDiscoverable);
EXPECT_EQ(adapter_b_->GetScanMode(),
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
ASSERT_TRUE(found_latch.Await().Ok());
std::string service_name{"service"};
std::string service_uuid("service-uuid");
BluetoothServerSocket server_socket =
bt_b_->ListenForService(service_name, service_uuid);
ASSERT_TRUE(server_socket.IsValid());
{
ByteArray data("data");
CancellationFlag flag;
SingleThreadExecutor server_executor;
SingleThreadExecutor client_executor;
client_executor.Execute([&, this]() {
BluetoothSocket socket_a =
bt_a_->ConnectToService(*discovered_device, service_uuid, &flag);
ASSERT_TRUE(socket_a.IsValid());
socket_a.Close();
EXPECT_FALSE(socket_a.GetOutputStream().Write(data).Ok());
});
server_executor.Execute([&]() {
BluetoothSocket socket_b = server_socket.Accept();
ASSERT_TRUE(socket_b.IsValid());
socket_b.Close();
EXPECT_FALSE(socket_b.GetInputStream().Read(data.size()).ok());
});
}
server_socket.Close();
}
TEST_F(BluetoothClassicMediumTest, ConstructorDestructorWorks) {
// Make sure we can create functional adapters.
ASSERT_TRUE(adapter_a_->IsValid());
@@ -21,6 +21,7 @@
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
@@ -52,8 +53,11 @@ bool BluetoothSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& BluetoothSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
if (remote_socket != nullptr) {
return remote_socket->GetLocalInputStream();
} else {
return invalid_input_stream_;
}
}
OutputStream& BluetoothSocket::GetOutputStream() {
@@ -92,6 +92,19 @@ class BluetoothSocket : public api::BluetoothSocket {
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
class InvalidInputStream : public InputStream {
public:
ExceptionOr<ByteArray> Read(std::int64_t size) override {
return ExceptionOr<ByteArray>(Exception::kIo);
}
ExceptionOr<size_t> Skip(size_t offset) override {
return ExceptionOr<size_t>(Exception::kIo);
}
Exception Close() override { return {Exception::kIo}; }
};
// Returned to the caller if the remote socket is destroyed.
InvalidInputStream invalid_input_stream_;
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.