cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / net / socket / unix_domain_socket_posix_unittest.cc
blob65fda0498cdd3bbd444a1fd60e03cbc4c4f28098
1 // Copyright (c) 2012 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 <errno.h>
6 #include <fcntl.h>
7 #include <poll.h>
8 #include <sys/socket.h>
9 #include <sys/stat.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12 #include <sys/un.h>
13 #include <unistd.h>
15 #include <cstring>
16 #include <queue>
17 #include <string>
19 #include "base/bind.h"
20 #include "base/callback.h"
21 #include "base/compiler_specific.h"
22 #include "base/file_util.h"
23 #include "base/files/file_path.h"
24 #include "base/memory/ref_counted.h"
25 #include "base/memory/scoped_ptr.h"
26 #include "base/message_loop/message_loop.h"
27 #include "base/posix/eintr_wrapper.h"
28 #include "base/synchronization/condition_variable.h"
29 #include "base/synchronization/lock.h"
30 #include "base/threading/platform_thread.h"
31 #include "base/threading/thread.h"
32 #include "net/socket/socket_descriptor.h"
33 #include "net/socket/unix_domain_socket_posix.h"
34 #include "testing/gtest/include/gtest/gtest.h"
36 using std::queue;
37 using std::string;
39 namespace net {
40 namespace {
42 const char kSocketFilename[] = "unix_domain_socket_for_testing";
43 const char kFallbackSocketName[] = "unix_domain_socket_for_testing_2";
44 const char kInvalidSocketPath[] = "/invalid/path";
45 const char kMsg[] = "hello";
47 enum EventType {
48 EVENT_ACCEPT,
49 EVENT_AUTH_DENIED,
50 EVENT_AUTH_GRANTED,
51 EVENT_CLOSE,
52 EVENT_LISTEN,
53 EVENT_READ,
56 string MakeSocketPath(const string& socket_file_name) {
57 base::FilePath temp_dir;
58 file_util::GetTempDir(&temp_dir);
59 return temp_dir.Append(socket_file_name).value();
62 string MakeSocketPath() {
63 return MakeSocketPath(kSocketFilename);
66 class EventManager : public base::RefCounted<EventManager> {
67 public:
68 EventManager() : condition_(&mutex_) {}
70 bool HasPendingEvent() {
71 base::AutoLock lock(mutex_);
72 return !events_.empty();
75 void Notify(EventType event) {
76 base::AutoLock lock(mutex_);
77 events_.push(event);
78 condition_.Broadcast();
81 EventType WaitForEvent() {
82 base::AutoLock lock(mutex_);
83 while (events_.empty())
84 condition_.Wait();
85 EventType event = events_.front();
86 events_.pop();
87 return event;
90 private:
91 friend class base::RefCounted<EventManager>;
92 virtual ~EventManager() {}
94 queue<EventType> events_;
95 base::Lock mutex_;
96 base::ConditionVariable condition_;
99 class TestListenSocketDelegate : public StreamListenSocket::Delegate {
100 public:
101 explicit TestListenSocketDelegate(
102 const scoped_refptr<EventManager>& event_manager)
103 : event_manager_(event_manager) {}
105 virtual void DidAccept(StreamListenSocket* server,
106 StreamListenSocket* connection) OVERRIDE {
107 LOG(ERROR) << __PRETTY_FUNCTION__;
108 connection_ = connection;
109 Notify(EVENT_ACCEPT);
112 virtual void DidRead(StreamListenSocket* connection,
113 const char* data,
114 int len) OVERRIDE {
116 base::AutoLock lock(mutex_);
117 DCHECK(len);
118 data_.assign(data, len - 1);
120 Notify(EVENT_READ);
123 virtual void DidClose(StreamListenSocket* sock) OVERRIDE {
124 Notify(EVENT_CLOSE);
127 void OnListenCompleted() {
128 Notify(EVENT_LISTEN);
131 string ReceivedData() {
132 base::AutoLock lock(mutex_);
133 return data_;
136 private:
137 void Notify(EventType event) {
138 event_manager_->Notify(event);
141 const scoped_refptr<EventManager> event_manager_;
142 scoped_refptr<StreamListenSocket> connection_;
143 base::Lock mutex_;
144 string data_;
147 bool UserCanConnectCallback(
148 bool allow_user, const scoped_refptr<EventManager>& event_manager,
149 uid_t, gid_t) {
150 event_manager->Notify(
151 allow_user ? EVENT_AUTH_GRANTED : EVENT_AUTH_DENIED);
152 return allow_user;
155 class UnixDomainSocketTestHelper : public testing::Test {
156 public:
157 void CreateAndListen() {
158 socket_ = UnixDomainSocket::CreateAndListen(
159 file_path_.value(), socket_delegate_.get(), MakeAuthCallback());
160 socket_delegate_->OnListenCompleted();
163 protected:
164 UnixDomainSocketTestHelper(const string& path, bool allow_user)
165 : file_path_(path),
166 allow_user_(allow_user) {}
168 virtual void SetUp() OVERRIDE {
169 event_manager_ = new EventManager();
170 socket_delegate_.reset(new TestListenSocketDelegate(event_manager_));
171 DeleteSocketFile();
174 virtual void TearDown() OVERRIDE {
175 DeleteSocketFile();
176 socket_ = NULL;
177 socket_delegate_.reset();
178 event_manager_ = NULL;
181 UnixDomainSocket::AuthCallback MakeAuthCallback() {
182 return base::Bind(&UserCanConnectCallback, allow_user_, event_manager_);
185 void DeleteSocketFile() {
186 ASSERT_FALSE(file_path_.empty());
187 base::DeleteFile(file_path_, false /* not recursive */);
190 SocketDescriptor CreateClientSocket() {
191 const SocketDescriptor sock = CreatePlatformSocket(PF_UNIX, SOCK_STREAM, 0);
192 if (sock < 0) {
193 LOG(ERROR) << "socket() error";
194 return kInvalidSocket;
196 sockaddr_un addr;
197 memset(&addr, 0, sizeof(addr));
198 addr.sun_family = AF_UNIX;
199 socklen_t addr_len;
200 strncpy(addr.sun_path, file_path_.value().c_str(), sizeof(addr.sun_path));
201 addr_len = sizeof(sockaddr_un);
202 if (connect(sock, reinterpret_cast<sockaddr*>(&addr), addr_len) != 0) {
203 LOG(ERROR) << "connect() error";
204 return kInvalidSocket;
206 return sock;
209 scoped_ptr<base::Thread> CreateAndRunServerThread() {
210 base::Thread::Options options;
211 options.message_loop_type = base::MessageLoop::TYPE_IO;
212 scoped_ptr<base::Thread> thread(new base::Thread("socketio_test"));
213 thread->StartWithOptions(options);
214 thread->message_loop()->PostTask(
215 FROM_HERE,
216 base::Bind(&UnixDomainSocketTestHelper::CreateAndListen,
217 base::Unretained(this)));
218 return thread.Pass();
221 const base::FilePath file_path_;
222 const bool allow_user_;
223 scoped_refptr<EventManager> event_manager_;
224 scoped_ptr<TestListenSocketDelegate> socket_delegate_;
225 scoped_refptr<UnixDomainSocket> socket_;
228 class UnixDomainSocketTest : public UnixDomainSocketTestHelper {
229 protected:
230 UnixDomainSocketTest()
231 : UnixDomainSocketTestHelper(MakeSocketPath(), true /* allow user */) {}
234 class UnixDomainSocketTestWithInvalidPath : public UnixDomainSocketTestHelper {
235 protected:
236 UnixDomainSocketTestWithInvalidPath()
237 : UnixDomainSocketTestHelper(kInvalidSocketPath, true) {}
240 class UnixDomainSocketTestWithForbiddenUser
241 : public UnixDomainSocketTestHelper {
242 protected:
243 UnixDomainSocketTestWithForbiddenUser()
244 : UnixDomainSocketTestHelper(MakeSocketPath(), false /* forbid user */) {}
247 TEST_F(UnixDomainSocketTest, CreateAndListen) {
248 CreateAndListen();
249 EXPECT_FALSE(socket_.get() == NULL);
252 TEST_F(UnixDomainSocketTestWithInvalidPath, CreateAndListenWithInvalidPath) {
253 CreateAndListen();
254 EXPECT_TRUE(socket_.get() == NULL);
257 #ifdef SOCKET_ABSTRACT_NAMESPACE_SUPPORTED
258 // Test with an invalid path to make sure that the socket is not backed by a
259 // file.
260 TEST_F(UnixDomainSocketTestWithInvalidPath,
261 CreateAndListenWithAbstractNamespace) {
262 socket_ = UnixDomainSocket::CreateAndListenWithAbstractNamespace(
263 file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
264 EXPECT_FALSE(socket_.get() == NULL);
267 TEST_F(UnixDomainSocketTest, TestFallbackName) {
268 scoped_refptr<UnixDomainSocket> existing_socket =
269 UnixDomainSocket::CreateAndListenWithAbstractNamespace(
270 file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
271 EXPECT_FALSE(existing_socket.get() == NULL);
272 // First, try to bind socket with the same name with no fallback name.
273 socket_ =
274 UnixDomainSocket::CreateAndListenWithAbstractNamespace(
275 file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
276 EXPECT_TRUE(socket_.get() == NULL);
277 // Now with a fallback name.
278 socket_ = UnixDomainSocket::CreateAndListenWithAbstractNamespace(
279 file_path_.value(),
280 MakeSocketPath(kFallbackSocketName),
281 socket_delegate_.get(),
282 MakeAuthCallback());
283 EXPECT_FALSE(socket_.get() == NULL);
284 existing_socket = NULL;
286 #endif
288 TEST_F(UnixDomainSocketTest, TestWithClient) {
289 const scoped_ptr<base::Thread> server_thread = CreateAndRunServerThread();
290 EventType event = event_manager_->WaitForEvent();
291 ASSERT_EQ(EVENT_LISTEN, event);
293 // Create the client socket.
294 const SocketDescriptor sock = CreateClientSocket();
295 ASSERT_NE(kInvalidSocket, sock);
296 event = event_manager_->WaitForEvent();
297 ASSERT_EQ(EVENT_AUTH_GRANTED, event);
298 event = event_manager_->WaitForEvent();
299 ASSERT_EQ(EVENT_ACCEPT, event);
301 // Send a message from the client to the server.
302 ssize_t ret = HANDLE_EINTR(send(sock, kMsg, sizeof(kMsg), 0));
303 ASSERT_NE(-1, ret);
304 ASSERT_EQ(sizeof(kMsg), static_cast<size_t>(ret));
305 event = event_manager_->WaitForEvent();
306 ASSERT_EQ(EVENT_READ, event);
307 ASSERT_EQ(kMsg, socket_delegate_->ReceivedData());
309 // Close the client socket.
310 ret = HANDLE_EINTR(close(sock));
311 event = event_manager_->WaitForEvent();
312 ASSERT_EQ(EVENT_CLOSE, event);
315 TEST_F(UnixDomainSocketTestWithForbiddenUser, TestWithForbiddenUser) {
316 const scoped_ptr<base::Thread> server_thread = CreateAndRunServerThread();
317 EventType event = event_manager_->WaitForEvent();
318 ASSERT_EQ(EVENT_LISTEN, event);
319 const SocketDescriptor sock = CreateClientSocket();
320 ASSERT_NE(kInvalidSocket, sock);
322 event = event_manager_->WaitForEvent();
323 ASSERT_EQ(EVENT_AUTH_DENIED, event);
325 // Wait until the file descriptor is closed by the server.
326 struct pollfd poll_fd;
327 poll_fd.fd = sock;
328 poll_fd.events = POLLIN;
329 poll(&poll_fd, 1, -1 /* rely on GTest for timeout handling */);
331 // Send() must fail.
332 ssize_t ret = HANDLE_EINTR(send(sock, kMsg, sizeof(kMsg), 0));
333 ASSERT_EQ(-1, ret);
334 ASSERT_EQ(EPIPE, errno);
335 ASSERT_FALSE(event_manager_->HasPendingEvent());
338 } // namespace
339 } // namespace net