Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: net/base/unix_domain_socket_posix_unittest.cc

Issue 13812005: net: move socket files from net/base to net/socket (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sort gyp Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/unix_domain_socket_posix.cc ('k') | net/net.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
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>
14
15 #include <cstring>
16 #include <queue>
17 #include <string>
18
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.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/base/unix_domain_socket_posix.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 using std::queue;
36 using std::string;
37
38 namespace net {
39 namespace {
40
41 const char kSocketFilename[] = "unix_domain_socket_for_testing";
42 const char kInvalidSocketPath[] = "/invalid/path";
43 const char kMsg[] = "hello";
44
45 enum EventType {
46 EVENT_ACCEPT,
47 EVENT_AUTH_DENIED,
48 EVENT_AUTH_GRANTED,
49 EVENT_CLOSE,
50 EVENT_LISTEN,
51 EVENT_READ,
52 };
53
54 string MakeSocketPath() {
55 base::FilePath temp_dir;
56 file_util::GetTempDir(&temp_dir);
57 return temp_dir.Append(kSocketFilename).value();
58 }
59
60 class EventManager : public base::RefCounted<EventManager> {
61 public:
62 EventManager() : condition_(&mutex_) {}
63
64 bool HasPendingEvent() {
65 base::AutoLock lock(mutex_);
66 return !events_.empty();
67 }
68
69 void Notify(EventType event) {
70 base::AutoLock lock(mutex_);
71 events_.push(event);
72 condition_.Broadcast();
73 }
74
75 EventType WaitForEvent() {
76 base::AutoLock lock(mutex_);
77 while (events_.empty())
78 condition_.Wait();
79 EventType event = events_.front();
80 events_.pop();
81 return event;
82 }
83
84 private:
85 friend class base::RefCounted<EventManager>;
86 virtual ~EventManager() {}
87
88 queue<EventType> events_;
89 base::Lock mutex_;
90 base::ConditionVariable condition_;
91 };
92
93 class TestListenSocketDelegate : public StreamListenSocket::Delegate {
94 public:
95 explicit TestListenSocketDelegate(
96 const scoped_refptr<EventManager>& event_manager)
97 : event_manager_(event_manager) {}
98
99 virtual void DidAccept(StreamListenSocket* server,
100 StreamListenSocket* connection) OVERRIDE {
101 LOG(ERROR) << __PRETTY_FUNCTION__;
102 connection_ = connection;
103 Notify(EVENT_ACCEPT);
104 }
105
106 virtual void DidRead(StreamListenSocket* connection,
107 const char* data,
108 int len) OVERRIDE {
109 {
110 base::AutoLock lock(mutex_);
111 DCHECK(len);
112 data_.assign(data, len - 1);
113 }
114 Notify(EVENT_READ);
115 }
116
117 virtual void DidClose(StreamListenSocket* sock) OVERRIDE {
118 Notify(EVENT_CLOSE);
119 }
120
121 void OnListenCompleted() {
122 Notify(EVENT_LISTEN);
123 }
124
125 string ReceivedData() {
126 base::AutoLock lock(mutex_);
127 return data_;
128 }
129
130 private:
131 void Notify(EventType event) {
132 event_manager_->Notify(event);
133 }
134
135 const scoped_refptr<EventManager> event_manager_;
136 scoped_refptr<StreamListenSocket> connection_;
137 base::Lock mutex_;
138 string data_;
139 };
140
141 bool UserCanConnectCallback(
142 bool allow_user, const scoped_refptr<EventManager>& event_manager,
143 uid_t, gid_t) {
144 event_manager->Notify(
145 allow_user ? EVENT_AUTH_GRANTED : EVENT_AUTH_DENIED);
146 return allow_user;
147 }
148
149 class UnixDomainSocketTestHelper : public testing::Test {
150 public:
151 void CreateAndListen() {
152 socket_ = UnixDomainSocket::CreateAndListen(
153 file_path_.value(), socket_delegate_.get(), MakeAuthCallback());
154 socket_delegate_->OnListenCompleted();
155 }
156
157 protected:
158 UnixDomainSocketTestHelper(const string& path, bool allow_user)
159 : file_path_(path),
160 allow_user_(allow_user) {}
161
162 virtual void SetUp() OVERRIDE {
163 event_manager_ = new EventManager();
164 socket_delegate_.reset(new TestListenSocketDelegate(event_manager_));
165 DeleteSocketFile();
166 }
167
168 virtual void TearDown() OVERRIDE {
169 DeleteSocketFile();
170 socket_ = NULL;
171 socket_delegate_.reset();
172 event_manager_ = NULL;
173 }
174
175 UnixDomainSocket::AuthCallback MakeAuthCallback() {
176 return base::Bind(&UserCanConnectCallback, allow_user_, event_manager_);
177 }
178
179 void DeleteSocketFile() {
180 ASSERT_FALSE(file_path_.empty());
181 file_util::Delete(file_path_, false /* not recursive */);
182 }
183
184 SocketDescriptor CreateClientSocket() {
185 const SocketDescriptor sock = socket(PF_UNIX, SOCK_STREAM, 0);
186 if (sock < 0) {
187 LOG(ERROR) << "socket() error";
188 return StreamListenSocket::kInvalidSocket;
189 }
190 sockaddr_un addr;
191 memset(&addr, 0, sizeof(addr));
192 addr.sun_family = AF_UNIX;
193 socklen_t addr_len;
194 strncpy(addr.sun_path, file_path_.value().c_str(), sizeof(addr.sun_path));
195 addr_len = sizeof(sockaddr_un);
196 if (connect(sock, reinterpret_cast<sockaddr*>(&addr), addr_len) != 0) {
197 LOG(ERROR) << "connect() error";
198 return StreamListenSocket::kInvalidSocket;
199 }
200 return sock;
201 }
202
203 scoped_ptr<base::Thread> CreateAndRunServerThread() {
204 base::Thread::Options options;
205 options.message_loop_type = MessageLoop::TYPE_IO;
206 scoped_ptr<base::Thread> thread(new base::Thread("socketio_test"));
207 thread->StartWithOptions(options);
208 thread->message_loop()->PostTask(
209 FROM_HERE,
210 base::Bind(&UnixDomainSocketTestHelper::CreateAndListen,
211 base::Unretained(this)));
212 return thread.Pass();
213 }
214
215 const base::FilePath file_path_;
216 const bool allow_user_;
217 scoped_refptr<EventManager> event_manager_;
218 scoped_ptr<TestListenSocketDelegate> socket_delegate_;
219 scoped_refptr<UnixDomainSocket> socket_;
220 };
221
222 class UnixDomainSocketTest : public UnixDomainSocketTestHelper {
223 protected:
224 UnixDomainSocketTest()
225 : UnixDomainSocketTestHelper(MakeSocketPath(), true /* allow user */) {}
226 };
227
228 class UnixDomainSocketTestWithInvalidPath : public UnixDomainSocketTestHelper {
229 protected:
230 UnixDomainSocketTestWithInvalidPath()
231 : UnixDomainSocketTestHelper(kInvalidSocketPath, true) {}
232 };
233
234 class UnixDomainSocketTestWithForbiddenUser
235 : public UnixDomainSocketTestHelper {
236 protected:
237 UnixDomainSocketTestWithForbiddenUser()
238 : UnixDomainSocketTestHelper(MakeSocketPath(), false /* forbid user */) {}
239 };
240
241 TEST_F(UnixDomainSocketTest, CreateAndListen) {
242 CreateAndListen();
243 EXPECT_FALSE(socket_.get() == NULL);
244 }
245
246 TEST_F(UnixDomainSocketTestWithInvalidPath, CreateAndListenWithInvalidPath) {
247 CreateAndListen();
248 EXPECT_TRUE(socket_.get() == NULL);
249 }
250
251 #ifdef SOCKET_ABSTRACT_NAMESPACE_SUPPORTED
252 // Test with an invalid path to make sure that the socket is not backed by a
253 // file.
254 TEST_F(UnixDomainSocketTestWithInvalidPath,
255 CreateAndListenWithAbstractNamespace) {
256 socket_ = UnixDomainSocket::CreateAndListenWithAbstractNamespace(
257 file_path_.value(), socket_delegate_.get(), MakeAuthCallback());
258 EXPECT_FALSE(socket_.get() == NULL);
259 }
260 #endif
261
262 TEST_F(UnixDomainSocketTest, TestWithClient) {
263 const scoped_ptr<base::Thread> server_thread = CreateAndRunServerThread();
264 EventType event = event_manager_->WaitForEvent();
265 ASSERT_EQ(EVENT_LISTEN, event);
266
267 // Create the client socket.
268 const SocketDescriptor sock = CreateClientSocket();
269 ASSERT_NE(StreamListenSocket::kInvalidSocket, sock);
270 event = event_manager_->WaitForEvent();
271 ASSERT_EQ(EVENT_AUTH_GRANTED, event);
272 event = event_manager_->WaitForEvent();
273 ASSERT_EQ(EVENT_ACCEPT, event);
274
275 // Send a message from the client to the server.
276 ssize_t ret = HANDLE_EINTR(send(sock, kMsg, sizeof(kMsg), 0));
277 ASSERT_NE(-1, ret);
278 ASSERT_EQ(sizeof(kMsg), static_cast<size_t>(ret));
279 event = event_manager_->WaitForEvent();
280 ASSERT_EQ(EVENT_READ, event);
281 ASSERT_EQ(kMsg, socket_delegate_->ReceivedData());
282
283 // Close the client socket.
284 ret = HANDLE_EINTR(close(sock));
285 event = event_manager_->WaitForEvent();
286 ASSERT_EQ(EVENT_CLOSE, event);
287 }
288
289 TEST_F(UnixDomainSocketTestWithForbiddenUser, TestWithForbiddenUser) {
290 const scoped_ptr<base::Thread> server_thread = CreateAndRunServerThread();
291 EventType event = event_manager_->WaitForEvent();
292 ASSERT_EQ(EVENT_LISTEN, event);
293 const SocketDescriptor sock = CreateClientSocket();
294 ASSERT_NE(StreamListenSocket::kInvalidSocket, sock);
295
296 event = event_manager_->WaitForEvent();
297 ASSERT_EQ(EVENT_AUTH_DENIED, event);
298
299 // Wait until the file descriptor is closed by the server.
300 struct pollfd poll_fd;
301 poll_fd.fd = sock;
302 poll_fd.events = POLLIN;
303 poll(&poll_fd, 1, -1 /* rely on GTest for timeout handling */);
304
305 // Send() must fail.
306 ssize_t ret = HANDLE_EINTR(send(sock, kMsg, sizeof(kMsg), 0));
307 ASSERT_EQ(-1, ret);
308 ASSERT_EQ(EPIPE, errno);
309 ASSERT_FALSE(event_manager_->HasPendingEvent());
310 }
311
312 } // namespace
313 } // namespace net
OLDNEW
« no previous file with comments | « net/base/unix_domain_socket_posix.cc ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698