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