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/synchronization/waitable_event.h" | |
11 #include "base/threading/thread.h" | |
12 #include "base/threading/thread_restrictions.h" | |
13 #include "ipc/unix_domain_socket_util.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace { | |
17 | |
18 class SocketAcceptor : public MessageLoopForIO::Watcher { | |
19 public: | |
20 SocketAcceptor(int fd, base::MessageLoopProxy* target_thread) | |
21 : server_fd_(-1), | |
22 started_watching_event_(false, false), | |
23 accepted_event_(false, false) { | |
24 target_thread->PostTask(FROM_HERE, | |
25 base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd)); | |
26 } | |
27 | |
28 virtual ~SocketAcceptor() { | |
29 watcher_.StopWatchingFileDescriptor(); | |
30 } | |
31 | |
32 int server_fd() const { return server_fd_; } | |
33 | |
34 void WaitUntilReady() { | |
35 started_watching_event_.Wait(); | |
36 } | |
37 void WaitForAccept() { | |
38 accepted_event_.Wait(); | |
39 } | |
40 | |
41 private: | |
42 void StartWatching(int fd) { | |
43 MessageLoopForIO::current()->WatchFileDescriptor( | |
44 fd, | |
45 true, | |
46 MessageLoopForIO::WATCH_READ, | |
47 &watcher_, | |
48 this); | |
49 started_watching_event_.Signal(); | |
50 } | |
51 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { | |
52 ASSERT_EQ(-1, server_fd_); | |
53 IPC::ServerAcceptConnection(fd, &server_fd_); | |
54 watcher_.StopWatchingFileDescriptor(); | |
55 accepted_event_.Signal(); | |
56 } | |
57 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} | |
58 | |
59 int server_fd_; | |
60 MessageLoopForIO::FileDescriptorWatcher watcher_; | |
61 base::WaitableEvent started_watching_event_; | |
62 base::WaitableEvent accepted_event_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(SocketAcceptor); | |
65 }; | |
66 | |
67 base::FilePath GetChannelDir() { | |
68 return base::FilePath("/var/tmp"); | |
69 } | |
70 | |
71 class TestUnixSocketConnection { | |
72 public: | |
73 TestUnixSocketConnection() | |
74 : worker_("WorkerThread"), | |
75 server_listen_fd_(-1), | |
76 server_fd_(-1), | |
77 client_fd_(-1), | |
78 acceptor_(NULL) { | |
79 socket_name_ = GetChannelDir().Append("TestSocket"); | |
80 base::Thread::Options options; | |
81 options.message_loop_type = MessageLoop::TYPE_IO; | |
82 worker_.StartWithOptions(options); | |
83 } | |
84 | |
85 bool CreateServerSocket() { | |
86 IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_); | |
87 if (server_listen_fd_ < 0) | |
88 return false; | |
89 struct stat socket_stat; | |
90 stat(socket_name_.value().c_str(), &socket_stat); | |
91 EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode)); | |
92 acceptor_ = new SocketAcceptor(server_listen_fd_, | |
93 worker_.message_loop_proxy()); | |
94 acceptor_->WaitUntilReady(); | |
95 return true; | |
96 } | |
97 | |
98 bool CreateClientSocket() { | |
99 DCHECK(server_listen_fd_ >= 0); | |
100 IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_); | |
101 if (client_fd_ < 0) | |
102 return false; | |
103 acceptor_->WaitForAccept(); | |
104 server_fd_ = acceptor_->server_fd(); | |
105 return server_fd_ >= 0; | |
106 } | |
107 | |
108 virtual ~TestUnixSocketConnection() { | |
109 if (acceptor_) | |
Mark Mentovai
2013/03/06 19:34:04
If you used scoped_ptr and ScopedFD, your destruct
jeremya
2013/03/06 21:46:01
I won't use ScopedFD because I want to unlink() af
| |
110 delete acceptor_; | |
111 if (client_fd_) | |
Mark Mentovai
2013/03/06 19:34:04
And if you don’t use ScopedFD, you need to teach t
jeremya
2013/03/06 21:46:01
Done.
| |
112 close(client_fd_); | |
113 if (server_fd_) | |
114 close(server_fd_); | |
115 if (server_listen_fd_) { | |
116 close(server_listen_fd_); | |
117 unlink(socket_name_.value().c_str()); | |
118 } | |
119 } | |
120 | |
121 int client_fd() { return client_fd_; } | |
Mark Mentovai
2013/03/06 19:34:04
These two methods can be const (like the one above
jeremya
2013/03/06 21:46:01
Done.
| |
122 int server_fd() { return server_fd_; } | |
123 | |
124 private: | |
125 base::Thread worker_; | |
126 base::FilePath socket_name_; | |
127 int server_listen_fd_; | |
128 int server_fd_; | |
129 int client_fd_; | |
130 SocketAcceptor* acceptor_; | |
131 }; | |
132 | |
133 // Ensure that IPC::CreateServerUnixDomainSocket creates a socket that | |
134 // IPC::CreateClientUnixDomainSocket can successfully connect to. | |
135 TEST(UnixDomainSocketUtil, Connect) { | |
136 TestUnixSocketConnection connection; | |
137 ASSERT_TRUE(connection.CreateServerSocket()); | |
138 ASSERT_TRUE(connection.CreateClientSocket()); | |
139 } | |
140 | |
141 // Ensure that messages can be sent across the resulting socket. | |
142 TEST(UnixDomainSocketUtil, SendReceive) { | |
143 TestUnixSocketConnection connection; | |
144 ASSERT_TRUE(connection.CreateServerSocket()); | |
145 ASSERT_TRUE(connection.CreateClientSocket()); | |
146 | |
147 const char buffer[] = "Hello, server!"; | |
148 size_t buf_len = sizeof(buffer); | |
149 size_t sent_bytes = | |
150 HANDLE_EINTR(send(connection.client_fd(), buffer, buf_len, 0)); | |
151 ASSERT_EQ(buf_len, sent_bytes); | |
152 char recv_buf[sizeof(buffer)]; | |
153 size_t received_bytes = | |
154 HANDLE_EINTR(recv(connection.server_fd(), recv_buf, buf_len, 0)); | |
155 ASSERT_EQ(buf_len, received_bytes); | |
156 ASSERT_EQ(0, memcmp(recv_buf, buffer, buf_len)); | |
157 } | |
158 | |
159 } // namespace | |
OLD | NEW |