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() { return server_fd_; } | |
Mark Mentovai
2013/03/05 20:08:03
This method can be const, just for kicks.
jeremya
2013/03/06 05:03:18
Done.
| |
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 // TODO stat socket_name and check that there's a socket present | |
Mark Mentovai
2013/03/05 20:08:03
OK, so do this.
jeremya
2013/03/06 05:03:18
Done.
| |
90 acceptor_ = new SocketAcceptor(server_listen_fd_, | |
91 worker_.message_loop_proxy()); | |
92 acceptor_->WaitUntilReady(); | |
93 return true; | |
94 } | |
95 | |
96 bool CreateClientSocket() { | |
97 DCHECK(server_listen_fd_ >= 0); | |
98 IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_); | |
99 if (client_fd_ < 0) | |
100 return false; | |
101 acceptor_->WaitForAccept(); | |
102 server_fd_ = acceptor_->server_fd(); | |
103 return server_fd_ >= 0; | |
104 } | |
105 | |
106 virtual ~TestUnixSocketConnection() { | |
107 if (acceptor_) | |
108 delete acceptor_; | |
109 if (client_fd_) | |
110 close(client_fd_); | |
111 if (server_fd_) | |
112 close(server_fd_); | |
113 if (server_listen_fd_) { | |
114 close(server_listen_fd_); | |
115 unlink(socket_name_.value().c_str()); | |
116 } | |
117 } | |
118 | |
119 int client_fd() { return client_fd_; } | |
120 int server_fd() { return server_fd_; } | |
121 | |
122 private: | |
123 base::Thread worker_; | |
124 base::FilePath socket_name_; | |
125 int server_listen_fd_; | |
126 int server_fd_; | |
127 int client_fd_; | |
128 SocketAcceptor* acceptor_; | |
129 }; | |
130 | |
131 // Ensure that IPC::CreateServerUnixDomainSocket creates a socket that | |
132 // IPC::CreateClientUnixDomainSocket can successfully connect to. | |
133 TEST(UnixDomainSocketUtil, Connect) { | |
134 TestUnixSocketConnection connection; | |
135 ASSERT_TRUE(connection.CreateServerSocket()); | |
136 ASSERT_TRUE(connection.CreateClientSocket()); | |
137 } | |
138 | |
139 // Ensure that messages can be sent across the resulting socket. | |
140 TEST(UnixDomainSocketUtil, SendReceive) { | |
141 TestUnixSocketConnection connection; | |
142 ASSERT_TRUE(connection.CreateServerSocket()); | |
143 ASSERT_TRUE(connection.CreateClientSocket()); | |
144 | |
145 const char buffer[] = "Hello, server!"; | |
146 size_t buf_len = strlen(buffer) + 1; | |
Mark Mentovai
2013/03/05 20:08:03
You could just use sizeof(buffer).
jeremya
2013/03/06 05:03:18
Done.
| |
147 size_t sent_bytes = send(connection.client_fd(), buffer, buf_len, 0); | |
Mark Mentovai
2013/03/05 20:08:03
HANDLE_EINTR here and on line 151.
jeremya
2013/03/06 05:03:18
Done.
| |
148 ASSERT_EQ(buf_len, sent_bytes); | |
149 scoped_array<char> recv_buf(new char[buf_len]); | |
Mark Mentovai
2013/03/05 20:08:03
You could just have a char recv_buf[sizeof(buffer)
jeremya
2013/03/06 05:03:18
Done.
| |
150 size_t received_bytes = | |
151 recv(connection.server_fd(), recv_buf.get(), buf_len, 0); | |
152 ASSERT_EQ(buf_len, received_bytes); | |
153 ASSERT_EQ(0, strncmp(recv_buf.get(), buffer, buf_len)); | |
Mark Mentovai
2013/03/05 20:08:03
Use memcmp. You have sizes in hand and you want to
jeremya
2013/03/06 05:03:18
Done.
| |
154 } | |
155 | |
156 } | |
Mark Mentovai
2013/03/05 20:08:03
} // namespace
jeremya
2013/03/06 05:03:18
Done.
| |
OLD | NEW |