1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/sync_socket.h"
6
7 #include "base/memory/raw_ptr.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/threading/platform_thread.h"
10 #include "base/threading/simple_thread.h"
11 #include "base/time/time.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base {
15
16 namespace {
17
18 constexpr TimeDelta kReceiveTimeout = base::Milliseconds(750);
19
20 class HangingReceiveThread : public DelegateSimpleThread::Delegate {
21 public:
HangingReceiveThread(SyncSocket * socket,bool with_timeout)22 explicit HangingReceiveThread(SyncSocket* socket, bool with_timeout)
23 : socket_(socket),
24 thread_(this, "HangingReceiveThread"),
25 with_timeout_(with_timeout),
26 started_event_(WaitableEvent::ResetPolicy::MANUAL,
27 WaitableEvent::InitialState::NOT_SIGNALED),
28 done_event_(WaitableEvent::ResetPolicy::MANUAL,
29 WaitableEvent::InitialState::NOT_SIGNALED) {
30 thread_.Start();
31 }
32
33 HangingReceiveThread(const HangingReceiveThread&) = delete;
34 HangingReceiveThread& operator=(const HangingReceiveThread&) = delete;
35 ~HangingReceiveThread() override = default;
36
Run()37 void Run() override {
38 int data = 0;
39 ASSERT_EQ(socket_->Peek(), 0u);
40
41 started_event_.Signal();
42
43 if (with_timeout_) {
44 ASSERT_EQ(0u, socket_->ReceiveWithTimeout(&data, sizeof(data),
45 kReceiveTimeout));
46 } else {
47 ASSERT_EQ(0u, socket_->Receive(&data, sizeof(data)));
48 }
49
50 done_event_.Signal();
51 }
52
Stop()53 void Stop() {
54 thread_.Join();
55 }
56
started_event()57 WaitableEvent* started_event() { return &started_event_; }
done_event()58 WaitableEvent* done_event() { return &done_event_; }
59
60 private:
61 raw_ptr<SyncSocket> socket_;
62 DelegateSimpleThread thread_;
63 bool with_timeout_;
64 WaitableEvent started_event_;
65 WaitableEvent done_event_;
66 };
67
68 // Tests sending data between two SyncSockets. Uses ASSERT() and thus will exit
69 // early upon failure. Callers should use ASSERT_NO_FATAL_FAILURE() if testing
70 // continues after return.
SendReceivePeek(SyncSocket * socket_a,SyncSocket * socket_b)71 void SendReceivePeek(SyncSocket* socket_a, SyncSocket* socket_b) {
72 int received = 0;
73 const int kSending = 123;
74 static_assert(sizeof(kSending) == sizeof(received), "invalid data size");
75
76 ASSERT_EQ(0u, socket_a->Peek());
77 ASSERT_EQ(0u, socket_b->Peek());
78
79 // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from
80 // |socket_a|.
81 ASSERT_EQ(sizeof(kSending),
82 socket_a->Send(as_bytes(make_span(&kSending, 1u))));
83 ASSERT_EQ(sizeof(kSending), socket_b->Peek());
84 ASSERT_EQ(sizeof(kSending),
85 socket_b->Receive(as_writable_bytes(make_span(&received, 1u))));
86 ASSERT_EQ(kSending, received);
87
88 ASSERT_EQ(0u, socket_a->Peek());
89 ASSERT_EQ(0u, socket_b->Peek());
90
91 // Now verify the reverse.
92 received = 0;
93 ASSERT_EQ(sizeof(kSending),
94 socket_b->Send(as_bytes(make_span(&kSending, 1u))));
95 ASSERT_EQ(sizeof(kSending), socket_a->Peek());
96 ASSERT_EQ(sizeof(kSending),
97 socket_a->Receive(as_writable_bytes(make_span(&received, 1u))));
98 ASSERT_EQ(kSending, received);
99
100 ASSERT_EQ(0u, socket_a->Peek());
101 ASSERT_EQ(0u, socket_b->Peek());
102
103 socket_a->Close();
104 socket_b->Close();
105 }
106
107 } // namespace
108
109 class SyncSocketTest : public testing::Test {
110 public:
SetUp()111 void SetUp() override {
112 ASSERT_TRUE(SyncSocket::CreatePair(&socket_a_, &socket_b_));
113 }
114
115 protected:
116 SyncSocket socket_a_;
117 SyncSocket socket_b_;
118 };
119
TEST_F(SyncSocketTest,NormalSendReceivePeek)120 TEST_F(SyncSocketTest, NormalSendReceivePeek) {
121 SendReceivePeek(&socket_a_, &socket_b_);
122 }
123
TEST_F(SyncSocketTest,ClonedSendReceivePeek)124 TEST_F(SyncSocketTest, ClonedSendReceivePeek) {
125 SyncSocket socket_c(socket_a_.Release());
126 SyncSocket socket_d(socket_b_.Release());
127 SendReceivePeek(&socket_c, &socket_d);
128 }
129
130 class CancelableSyncSocketTest : public testing::Test {
131 public:
SetUp()132 void SetUp() override {
133 ASSERT_TRUE(CancelableSyncSocket::CreatePair(&socket_a_, &socket_b_));
134 }
135
136 protected:
137 CancelableSyncSocket socket_a_;
138 CancelableSyncSocket socket_b_;
139 };
140
TEST_F(CancelableSyncSocketTest,NormalSendReceivePeek)141 TEST_F(CancelableSyncSocketTest, NormalSendReceivePeek) {
142 SendReceivePeek(&socket_a_, &socket_b_);
143 }
144
TEST_F(CancelableSyncSocketTest,ClonedSendReceivePeek)145 TEST_F(CancelableSyncSocketTest, ClonedSendReceivePeek) {
146 CancelableSyncSocket socket_c(socket_a_.Release());
147 CancelableSyncSocket socket_d(socket_b_.Release());
148 SendReceivePeek(&socket_c, &socket_d);
149 }
150
TEST_F(CancelableSyncSocketTest,ShutdownCancelsReceive)151 TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceive) {
152 HangingReceiveThread thread(&socket_b_, /* with_timeout = */ false);
153
154 // Wait for the thread to be started. Note that this doesn't guarantee that
155 // Receive() is called before Shutdown().
156 thread.started_event()->Wait();
157
158 EXPECT_TRUE(socket_b_.Shutdown());
159 EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout));
160
161 thread.Stop();
162 }
163
TEST_F(CancelableSyncSocketTest,ShutdownCancelsReceiveWithTimeout)164 TEST_F(CancelableSyncSocketTest, ShutdownCancelsReceiveWithTimeout) {
165 HangingReceiveThread thread(&socket_b_, /* with_timeout = */ true);
166
167 // Wait for the thread to be started. Note that this doesn't guarantee that
168 // Receive() is called before Shutdown().
169 thread.started_event()->Wait();
170
171 EXPECT_TRUE(socket_b_.Shutdown());
172 EXPECT_TRUE(thread.done_event()->TimedWait(kReceiveTimeout));
173
174 thread.Stop();
175 }
176
TEST_F(CancelableSyncSocketTest,ReceiveAfterShutdown)177 TEST_F(CancelableSyncSocketTest, ReceiveAfterShutdown) {
178 socket_a_.Shutdown();
179 int data = 0;
180 EXPECT_EQ(0u, socket_a_.Receive(as_writable_bytes(make_span(&data, 1u))));
181 }
182
TEST_F(CancelableSyncSocketTest,ReceiveWithTimeoutAfterShutdown)183 TEST_F(CancelableSyncSocketTest, ReceiveWithTimeoutAfterShutdown) {
184 socket_a_.Shutdown();
185 TimeTicks start = TimeTicks::Now();
186 int data = 0;
187 EXPECT_EQ(0u,
188 socket_a_.ReceiveWithTimeout(&data, sizeof(data), kReceiveTimeout));
189
190 // Ensure the receive didn't just timeout.
191 EXPECT_LT(TimeTicks::Now() - start, kReceiveTimeout);
192 }
193
194 } // namespace base
195