OLD | NEW |
| (Empty) |
1 // Copyright 2013 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. | |
4 | |
5 #include <sys/socket.h> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/files/file_path.h" | |
10 #include "base/path_service.h" | |
11 #include "base/synchronization/waitable_event.h" | |
12 #include "base/threading/thread.h" | |
13 #include "base/threading/thread_restrictions.h" | |
14 #include "ipc/unix_domain_socket_util.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace { | |
18 | |
19 class SocketAcceptor : public MessageLoopForIO::Watcher { | |
20 public: | |
21 SocketAcceptor(int fd, base::MessageLoopProxy* target_thread) | |
22 : server_fd_(-1), | |
23 target_thread_(target_thread), | |
24 started_watching_event_(false, false), | |
25 accepted_event_(false, false) { | |
26 target_thread->PostTask(FROM_HERE, | |
27 base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd)); | |
28 } | |
29 | |
30 virtual ~SocketAcceptor() { | |
31 Close(); | |
32 } | |
33 | |
34 int server_fd() const { return server_fd_; } | |
35 | |
36 void WaitUntilReady() { | |
37 started_watching_event_.Wait(); | |
38 } | |
39 void WaitForAccept() { | |
40 accepted_event_.Wait(); | |
41 } | |
42 | |
43 void Close() { | |
44 if (watcher_.get()) { | |
45 target_thread_->PostTask(FROM_HERE, | |
46 base::Bind(&SocketAcceptor::StopWatching, base::Unretained(this), | |
47 watcher_.release())); | |
48 } | |
49 } | |
50 | |
51 private: | |
52 void StartWatching(int fd) { | |
53 watcher_.reset(new MessageLoopForIO::FileDescriptorWatcher); | |
54 MessageLoopForIO::current()->WatchFileDescriptor( | |
55 fd, | |
56 true, | |
57 MessageLoopForIO::WATCH_READ, | |
58 watcher_.get(), | |
59 this); | |
60 started_watching_event_.Signal(); | |
61 } | |
62 void StopWatching(MessageLoopForIO::FileDescriptorWatcher* watcher) { | |
63 watcher->StopWatchingFileDescriptor(); | |
64 delete watcher; | |
65 } | |
66 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { | |
67 ASSERT_EQ(-1, server_fd_); | |
68 IPC::ServerAcceptConnection(fd, &server_fd_); | |
69 watcher_->StopWatchingFileDescriptor(); | |
70 accepted_event_.Signal(); | |
71 } | |
72 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} | |
73 | |
74 int server_fd_; | |
75 base::MessageLoopProxy* target_thread_; | |
76 scoped_ptr<MessageLoopForIO::FileDescriptorWatcher> watcher_; | |
77 base::WaitableEvent started_watching_event_; | |
78 base::WaitableEvent accepted_event_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(SocketAcceptor); | |
81 }; | |
82 | |
83 const base::FilePath GetChannelDir() { | |
84 #if defined(OS_ANDROID) | |
85 base::FilePath tmp_dir; | |
86 PathService::Get(base::DIR_CACHE, &tmp_dir); | |
87 return tmp_dir; | |
88 #else | |
89 return base::FilePath("/var/tmp"); | |
90 #endif | |
91 } | |
92 | |
93 class TestUnixSocketConnection { | |
94 public: | |
95 TestUnixSocketConnection() | |
96 : worker_("WorkerThread"), | |
97 server_listen_fd_(-1), | |
98 server_fd_(-1), | |
99 client_fd_(-1) { | |
100 socket_name_ = GetChannelDir().Append("TestSocket"); | |
101 base::Thread::Options options; | |
102 options.message_loop_type = MessageLoop::TYPE_IO; | |
103 worker_.StartWithOptions(options); | |
104 } | |
105 | |
106 bool CreateServerSocket() { | |
107 IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_); | |
108 if (server_listen_fd_ < 0) | |
109 return false; | |
110 struct stat socket_stat; | |
111 stat(socket_name_.value().c_str(), &socket_stat); | |
112 EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode)); | |
113 acceptor_.reset(new SocketAcceptor(server_listen_fd_, | |
114 worker_.message_loop_proxy())); | |
115 acceptor_->WaitUntilReady(); | |
116 return true; | |
117 } | |
118 | |
119 bool CreateClientSocket() { | |
120 DCHECK(server_listen_fd_ >= 0); | |
121 IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_); | |
122 if (client_fd_ < 0) | |
123 return false; | |
124 acceptor_->WaitForAccept(); | |
125 server_fd_ = acceptor_->server_fd(); | |
126 return server_fd_ >= 0; | |
127 } | |
128 | |
129 virtual ~TestUnixSocketConnection() { | |
130 if (client_fd_ >= 0) | |
131 close(client_fd_); | |
132 if (server_fd_ >= 0) | |
133 close(server_fd_); | |
134 if (server_listen_fd_ >= 0) { | |
135 close(server_listen_fd_); | |
136 unlink(socket_name_.value().c_str()); | |
137 } | |
138 } | |
139 | |
140 int client_fd() const { return client_fd_; } | |
141 int server_fd() const { return server_fd_; } | |
142 | |
143 private: | |
144 base::Thread worker_; | |
145 base::FilePath socket_name_; | |
146 int server_listen_fd_; | |
147 int server_fd_; | |
148 int client_fd_; | |
149 scoped_ptr<SocketAcceptor> acceptor_; | |
150 }; | |
151 | |
152 // Ensure that IPC::CreateServerUnixDomainSocket creates a socket that | |
153 // IPC::CreateClientUnixDomainSocket can successfully connect to. | |
154 TEST(UnixDomainSocketUtil, Connect) { | |
155 TestUnixSocketConnection connection; | |
156 ASSERT_TRUE(connection.CreateServerSocket()); | |
157 ASSERT_TRUE(connection.CreateClientSocket()); | |
158 } | |
159 | |
160 // Ensure that messages can be sent across the resulting socket. | |
161 TEST(UnixDomainSocketUtil, SendReceive) { | |
162 TestUnixSocketConnection connection; | |
163 ASSERT_TRUE(connection.CreateServerSocket()); | |
164 ASSERT_TRUE(connection.CreateClientSocket()); | |
165 | |
166 const char buffer[] = "Hello, server!"; | |
167 size_t buf_len = sizeof(buffer); | |
168 size_t sent_bytes = | |
169 HANDLE_EINTR(send(connection.client_fd(), buffer, buf_len, 0)); | |
170 ASSERT_EQ(buf_len, sent_bytes); | |
171 char recv_buf[sizeof(buffer)]; | |
172 size_t received_bytes = | |
173 HANDLE_EINTR(recv(connection.server_fd(), recv_buf, buf_len, 0)); | |
174 ASSERT_EQ(buf_len, received_bytes); | |
175 ASSERT_EQ(0, memcmp(recv_buf, buffer, buf_len)); | |
176 } | |
177 | |
178 } // namespace | |
OLD | NEW |