|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/sync_socket.h" | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/synchronization/waitable_event.h" | 
|  | #include "base/threading/platform_thread.h" | 
|  | #include "base/threading/simple_thread.h" | 
|  | #include "base/time/time.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr TimeDelta kReceiveTimeout = base::TimeDelta::FromMilliseconds(750); | 
|  |  | 
|  | class HangingReceiveThread : public DelegateSimpleThread::Delegate { | 
|  | public: | 
|  | explicit HangingReceiveThread(SyncSocket* socket, bool with_timeout) | 
|  | : socket_(socket), | 
|  | thread_(this, "HangingReceiveThread"), | 
|  | with_timeout_(with_timeout), | 
|  | started_event_(WaitableEvent::ResetPolicy::MANUAL, | 
|  | WaitableEvent::InitialState::NOT_SIGNALED), | 
|  | done_event_(WaitableEvent::ResetPolicy::MANUAL, | 
|  | WaitableEvent::InitialState::NOT_SIGNALED) { | 
|  | thread_.Start(); | 
|  | } | 
|  |  | 
|  | ~HangingReceiveThread() override = default; | 
|  |  | 
|  | void Run() override { | 
|  | int data = 0; | 
|  | ASSERT_EQ(socket_->Peek(), 0u); | 
|  |  | 
|  | started_event_.Signal(); | 
|  |  | 
|  | if (with_timeout_) { | 
|  | ASSERT_EQ(0u, socket_->ReceiveWithTimeout(&data, sizeof(data), | 
|  | kReceiveTimeout)); | 
|  | } else { | 
|  | ASSERT_EQ(0u, socket_->Receive(&data, sizeof(data))); | 
|  | } | 
|  |  | 
|  | done_event_.Signal(); | 
|  | } | 
|  |  | 
|  | void Stop() { | 
|  | thread_.Join(); | 
|  | } | 
|  |  | 
|  | WaitableEvent* started_event() { return &started_event_; } | 
|  | WaitableEvent* done_event() { return &done_event_; } | 
|  |  | 
|  | private: | 
|  | SyncSocket* socket_; | 
|  | DelegateSimpleThread thread_; | 
|  | bool with_timeout_; | 
|  | WaitableEvent started_event_; | 
|  | WaitableEvent done_event_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread); | 
|  | }; | 
|  |  | 
|  | // Tests sending data between two SyncSockets. Uses ASSERT() and thus will exit | 
|  | // early upon failure.  Callers should use ASSERT_NO_FATAL_FAILURE() if testing | 
|  | // continues after return. | 
|  | void SendReceivePeek(SyncSocket* socket_a, SyncSocket* socket_b) { | 
|  | int received = 0; | 
|  | const int kSending = 123; | 
|  | static_assert(sizeof(kSending) == sizeof(received), "invalid data size"); | 
|  |  | 
|  | ASSERT_EQ(0u, socket_a->Peek()); | 
|  | ASSERT_EQ(0u, socket_b->Peek()); | 
|  |  | 
|  | // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from | 
|  | // |socket_a|. | 
|  | ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending))); | 
|  | ASSERT_EQ(sizeof(kSending), socket_b->Peek()); | 
|  | ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending))); | 
|  | ASSERT_EQ(kSending, received); | 
|  |  | 
|  | ASSERT_EQ(0u, socket_a->Peek()); | 
|  | ASSERT_EQ(0u, socket_b->Peek()); | 
|  |  | 
|  | // Now verify the reverse. | 
|  | received = 0; | 
|  | ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending))); | 
|  | ASSERT_EQ(sizeof(kSending), socket_a->Peek()); | 
|  | ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending))); | 
|  | ASSERT_EQ(kSending, received); | 
|  |  | 
|  | ASSERT_EQ(0u, socket_a->Peek()); | 
|  | ASSERT_EQ(0u, socket_b->Peek()); | 
|  |  | 
|  | ASSERT_TRUE(socket_a->Close()); | 
|  | ASSERT_TRUE(socket_b->Close()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class SyncSocketTest : public testing::Test { | 
|  | public: | 
|  | void SetUp() override { | 
|  | ASSERT_TRUE(SyncSocket::CreatePair(&socket_a_, &socket_b_)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | SyncSocket socket_a_; | 
|  | SyncSocket socket_b_; | 
|  | }; | 
|  |  | 
|  | TEST_F(SyncSocketTest, NormalSendReceivePeek) { | 
|  | SendReceivePeek(&socket_a_, &socket_b_); | 
|  | } | 
|  |  | 
|  | TEST_F(SyncSocketTest, ClonedSendReceivePeek) { | 
|  | SyncSocket socket_c(socket_a_.Release()); | 
|  | SyncSocket socket_d(socket_b_.Release()); | 
|  | SendReceivePeek(&socket_c, &socket_d); | 
|  | }; | 
|  |  | 
|  | class CancelableSyncSocketTest : public testing::Test { | 
|  | public: | 
|  | void SetUp() override { | 
|  | ASSERT_TRUE(CancelableSyncSocket::CreatePair(&socket_a_, &socket_b_)); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | CancelableSyncSocket socket_a_; | 
|  | CancelableSyncSocket socket_b_; | 
|  | }; | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, NormalSendReceivePeek) { | 
|  | SendReceivePeek(&socket_a_, &socket_b_); | 
|  | } | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, ClonedSendReceivePeek) { | 
|  | CancelableSyncSocket socket_c(socket_a_.Release()); | 
|  | CancelableSyncSocket socket_d(socket_b_.Release()); | 
|  | SendReceivePeek(&socket_c, &socket_d); | 
|  | } | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceive) { | 
|  | HangingReceiveThread thread(&socket_b_, /* with_timeout = */ false); | 
|  |  | 
|  | // Wait for the thread to be started. Note that this doesn't guarantee that | 
|  | // Receive() is called before Shutdown(). | 
|  | thread.started_event()->Wait(); | 
|  |  | 
|  | EXPECT_TRUE(socket_b_.Shutdown()); | 
|  | EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); | 
|  |  | 
|  | thread.Stop(); | 
|  | } | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceiveWithTimeout) { | 
|  | HangingReceiveThread thread(&socket_b_, /* with_timeout = */ true); | 
|  |  | 
|  | // Wait for the thread to be started. Note that this doesn't guarantee that | 
|  | // Receive() is called before Shutdown(). | 
|  | thread.started_event()->Wait(); | 
|  |  | 
|  | EXPECT_TRUE(socket_b_.Shutdown()); | 
|  | EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout)); | 
|  |  | 
|  | thread.Stop(); | 
|  | } | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, ReceiveAfterShutdown) { | 
|  | socket_a_.Shutdown(); | 
|  | int data = 0; | 
|  | EXPECT_EQ(0u, socket_a_.Receive(&data, sizeof(data))); | 
|  | } | 
|  |  | 
|  | TEST_F(CancelableSyncSocketTest, ReceiveWithTimeoutAfterShutdown) { | 
|  | socket_a_.Shutdown(); | 
|  | TimeTicks start = TimeTicks::Now(); | 
|  | int data = 0; | 
|  | EXPECT_EQ(0u, | 
|  | socket_a_.ReceiveWithTimeout(&data, sizeof(data), kReceiveTimeout)); | 
|  |  | 
|  | // Ensure the receive didn't just timeout. | 
|  | EXPECT_LT(TimeTicks::Now() - start, kReceiveTimeout); | 
|  | } | 
|  |  | 
|  | }  // namespace base |