1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/socket/unix_domain_listen_socket_posix.h"
10 #include <sys/socket.h>
13 #include <sys/types.h>
21 #include "base/bind.h"
22 #include "base/callback.h"
23 #include "base/compiler_specific.h"
24 #include "base/files/file_path.h"
25 #include "base/files/file_util.h"
26 #include "base/files/scoped_temp_dir.h"
27 #include "base/memory/ref_counted.h"
28 #include "base/memory/scoped_ptr.h"
29 #include "base/message_loop/message_loop.h"
30 #include "base/posix/eintr_wrapper.h"
31 #include "base/synchronization/condition_variable.h"
32 #include "base/synchronization/lock.h"
33 #include "base/threading/platform_thread.h"
34 #include "base/threading/thread.h"
35 #include "net/socket/socket_descriptor.h"
36 #include "testing/gtest/include/gtest/gtest.h"
42 namespace deprecated
{
45 const char kSocketFilename
[] = "socket_for_testing";
46 const char kInvalidSocketPath
[] = "/invalid/path";
47 const char kMsg
[] = "hello";
58 class EventManager
: public base::RefCounted
<EventManager
> {
60 EventManager() : condition_(&mutex_
) {}
62 bool HasPendingEvent() {
63 base::AutoLock
lock(mutex_
);
64 return !events_
.empty();
67 void Notify(EventType event
) {
68 base::AutoLock
lock(mutex_
);
70 condition_
.Broadcast();
73 EventType
WaitForEvent() {
74 base::AutoLock
lock(mutex_
);
75 while (events_
.empty())
77 EventType event
= events_
.front();
83 friend class base::RefCounted
<EventManager
>;
84 virtual ~EventManager() {}
86 queue
<EventType
> events_
;
88 base::ConditionVariable condition_
;
91 class TestListenSocketDelegate
: public StreamListenSocket::Delegate
{
93 explicit TestListenSocketDelegate(
94 const scoped_refptr
<EventManager
>& event_manager
)
95 : event_manager_(event_manager
) {}
97 virtual void DidAccept(StreamListenSocket
* server
,
98 scoped_ptr
<StreamListenSocket
> connection
) OVERRIDE
{
99 LOG(ERROR
) << __PRETTY_FUNCTION__
;
100 connection_
= connection
.Pass();
101 Notify(EVENT_ACCEPT
);
104 virtual void DidRead(StreamListenSocket
* connection
,
108 base::AutoLock
lock(mutex_
);
110 data_
.assign(data
, len
- 1);
115 virtual void DidClose(StreamListenSocket
* sock
) OVERRIDE
{
119 void OnListenCompleted() {
120 Notify(EVENT_LISTEN
);
123 string
ReceivedData() {
124 base::AutoLock
lock(mutex_
);
129 void Notify(EventType event
) {
130 event_manager_
->Notify(event
);
133 const scoped_refptr
<EventManager
> event_manager_
;
134 scoped_ptr
<StreamListenSocket
> connection_
;
139 bool UserCanConnectCallback(
140 bool allow_user
, const scoped_refptr
<EventManager
>& event_manager
,
141 const UnixDomainServerSocket::Credentials
&) {
142 event_manager
->Notify(
143 allow_user
? EVENT_AUTH_GRANTED
: EVENT_AUTH_DENIED
);
147 class UnixDomainListenSocketTestHelper
: public testing::Test
{
149 void CreateAndListen() {
150 socket_
= UnixDomainListenSocket::CreateAndListen(
151 file_path_
.value(), socket_delegate_
.get(), MakeAuthCallback());
152 socket_delegate_
->OnListenCompleted();
156 UnixDomainListenSocketTestHelper(const string
& path_str
, bool allow_user
)
157 : allow_user_(allow_user
) {
158 file_path_
= base::FilePath(path_str
);
159 if (!file_path_
.IsAbsolute()) {
160 EXPECT_TRUE(temp_dir_
.CreateUniqueTempDir());
161 file_path_
= GetTempSocketPath(file_path_
.value());
163 // Beware that if path_str is an absolute path, this class doesn't delete
164 // the file. It must be an invalid path and cannot be created by unittests.
167 base::FilePath
GetTempSocketPath(const std::string socket_name
) {
168 DCHECK(temp_dir_
.IsValid());
169 return temp_dir_
.path().Append(socket_name
);
172 virtual void SetUp() OVERRIDE
{
173 event_manager_
= new EventManager();
174 socket_delegate_
.reset(new TestListenSocketDelegate(event_manager_
));
177 virtual void TearDown() OVERRIDE
{
179 socket_delegate_
.reset();
180 event_manager_
= NULL
;
183 UnixDomainListenSocket::AuthCallback
MakeAuthCallback() {
184 return base::Bind(&UserCanConnectCallback
, allow_user_
, event_manager_
);
187 SocketDescriptor
CreateClientSocket() {
188 const SocketDescriptor sock
= CreatePlatformSocket(PF_UNIX
, SOCK_STREAM
, 0);
190 LOG(ERROR
) << "socket() error";
191 return kInvalidSocket
;
194 memset(&addr
, 0, sizeof(addr
));
195 addr
.sun_family
= AF_UNIX
;
197 strncpy(addr
.sun_path
, file_path_
.value().c_str(), sizeof(addr
.sun_path
));
198 addr_len
= sizeof(sockaddr_un
);
199 if (connect(sock
, reinterpret_cast<sockaddr
*>(&addr
), addr_len
) != 0) {
200 LOG(ERROR
) << "connect() error: " << strerror(errno
)
201 << ": path=" << file_path_
.value();
202 return kInvalidSocket
;
207 scoped_ptr
<base::Thread
> CreateAndRunServerThread() {
208 base::Thread::Options options
;
209 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
210 scoped_ptr
<base::Thread
> thread(new base::Thread("socketio_test"));
211 thread
->StartWithOptions(options
);
212 thread
->message_loop()->PostTask(
214 base::Bind(&UnixDomainListenSocketTestHelper::CreateAndListen
,
215 base::Unretained(this)));
216 return thread
.Pass();
219 base::ScopedTempDir temp_dir_
;
220 base::FilePath file_path_
;
221 const bool allow_user_
;
222 scoped_refptr
<EventManager
> event_manager_
;
223 scoped_ptr
<TestListenSocketDelegate
> socket_delegate_
;
224 scoped_ptr
<UnixDomainListenSocket
> socket_
;
227 class UnixDomainListenSocketTest
: public UnixDomainListenSocketTestHelper
{
229 UnixDomainListenSocketTest()
230 : UnixDomainListenSocketTestHelper(kSocketFilename
,
231 true /* allow user */) {}
234 class UnixDomainListenSocketTestWithInvalidPath
235 : public UnixDomainListenSocketTestHelper
{
237 UnixDomainListenSocketTestWithInvalidPath()
238 : UnixDomainListenSocketTestHelper(kInvalidSocketPath
, true) {}
241 class UnixDomainListenSocketTestWithForbiddenUser
242 : public UnixDomainListenSocketTestHelper
{
244 UnixDomainListenSocketTestWithForbiddenUser()
245 : UnixDomainListenSocketTestHelper(kSocketFilename
,
246 false /* forbid user */) {}
249 TEST_F(UnixDomainListenSocketTest
, CreateAndListen
) {
251 EXPECT_FALSE(socket_
.get() == NULL
);
254 TEST_F(UnixDomainListenSocketTestWithInvalidPath
,
255 CreateAndListenWithInvalidPath
) {
257 EXPECT_TRUE(socket_
.get() == NULL
);
260 #ifdef SOCKET_ABSTRACT_NAMESPACE_SUPPORTED
261 // Test with an invalid path to make sure that the socket is not backed by a
263 TEST_F(UnixDomainListenSocketTestWithInvalidPath
,
264 CreateAndListenWithAbstractNamespace
) {
265 socket_
= UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
266 file_path_
.value(), "", socket_delegate_
.get(), MakeAuthCallback());
267 EXPECT_FALSE(socket_
.get() == NULL
);
270 TEST_F(UnixDomainListenSocketTest
, TestFallbackName
) {
271 scoped_ptr
<UnixDomainListenSocket
> existing_socket
=
272 UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
273 file_path_
.value(), "", socket_delegate_
.get(), MakeAuthCallback());
274 EXPECT_FALSE(existing_socket
.get() == NULL
);
275 // First, try to bind socket with the same name with no fallback name.
277 UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
278 file_path_
.value(), "", socket_delegate_
.get(), MakeAuthCallback());
279 EXPECT_TRUE(socket_
.get() == NULL
);
280 // Now with a fallback name.
281 const char kFallbackSocketName
[] = "socket_for_testing_2";
282 socket_
= UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
284 GetTempSocketPath(kFallbackSocketName
).value(),
285 socket_delegate_
.get(),
287 EXPECT_FALSE(socket_
.get() == NULL
);
291 TEST_F(UnixDomainListenSocketTest
, TestWithClient
) {
292 const scoped_ptr
<base::Thread
> server_thread
= CreateAndRunServerThread();
293 EventType event
= event_manager_
->WaitForEvent();
294 ASSERT_EQ(EVENT_LISTEN
, event
);
296 // Create the client socket.
297 const SocketDescriptor sock
= CreateClientSocket();
298 ASSERT_NE(kInvalidSocket
, sock
);
299 event
= event_manager_
->WaitForEvent();
300 ASSERT_EQ(EVENT_AUTH_GRANTED
, event
);
301 event
= event_manager_
->WaitForEvent();
302 ASSERT_EQ(EVENT_ACCEPT
, event
);
304 // Send a message from the client to the server.
305 ssize_t ret
= HANDLE_EINTR(send(sock
, kMsg
, sizeof(kMsg
), 0));
307 ASSERT_EQ(sizeof(kMsg
), static_cast<size_t>(ret
));
308 event
= event_manager_
->WaitForEvent();
309 ASSERT_EQ(EVENT_READ
, event
);
310 ASSERT_EQ(kMsg
, socket_delegate_
->ReceivedData());
312 // Close the client socket.
313 ret
= IGNORE_EINTR(close(sock
));
314 event
= event_manager_
->WaitForEvent();
315 ASSERT_EQ(EVENT_CLOSE
, event
);
318 TEST_F(UnixDomainListenSocketTestWithForbiddenUser
, TestWithForbiddenUser
) {
319 const scoped_ptr
<base::Thread
> server_thread
= CreateAndRunServerThread();
320 EventType event
= event_manager_
->WaitForEvent();
321 ASSERT_EQ(EVENT_LISTEN
, event
);
322 const SocketDescriptor sock
= CreateClientSocket();
323 ASSERT_NE(kInvalidSocket
, sock
);
325 event
= event_manager_
->WaitForEvent();
326 ASSERT_EQ(EVENT_AUTH_DENIED
, event
);
328 // Wait until the file descriptor is closed by the server.
329 struct pollfd poll_fd
;
331 poll_fd
.events
= POLLIN
;
332 poll(&poll_fd
, 1, -1 /* rely on GTest for timeout handling */);
335 ssize_t ret
= HANDLE_EINTR(send(sock
, kMsg
, sizeof(kMsg
), 0));
337 ASSERT_EQ(EPIPE
, errno
);
338 ASSERT_FALSE(event_manager_
->HasPendingEvent());
342 } // namespace deprecated