blob: 49c1c024c1f8f689ab579fec18a545a14edbc401 [file] [log] [blame]
[email protected]bdf9bdc2013-03-13 04:23:101// 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
avi246998d82015-12-22 02:39:045#include <stddef.h>
[email protected]bdf9bdc2013-03-13 04:23:106#include <sys/socket.h>
7
8#include "base/bind.h"
[email protected]bdf9bdc2013-03-13 04:23:109#include "base/files/file_path.h"
skyostile687bdff2015-05-12 11:29:2110#include "base/location.h"
avi246998d82015-12-22 02:39:0411#include "base/macros.h"
[email protected]bdf9bdc2013-03-13 04:23:1012#include "base/path_service.h"
[email protected]47163d42013-05-16 02:37:5013#include "base/posix/eintr_wrapper.h"
skyostile687bdff2015-05-12 11:29:2114#include "base/single_thread_task_runner.h"
[email protected]bdf9bdc2013-03-13 04:23:1015#include "base/synchronization/waitable_event.h"
16#include "base/threading/thread.h"
17#include "base/threading/thread_restrictions.h"
18#include "ipc/unix_domain_socket_util.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace {
22
[email protected]fd0a773a2013-04-30 20:55:0323class SocketAcceptor : public base::MessageLoopForIO::Watcher {
[email protected]bdf9bdc2013-03-13 04:23:1024 public:
skyostile687bdff2015-05-12 11:29:2125 SocketAcceptor(int fd, base::SingleThreadTaskRunner* target_thread)
[email protected]bdf9bdc2013-03-13 04:23:1026 : server_fd_(-1),
27 target_thread_(target_thread),
28 started_watching_event_(false, false),
29 accepted_event_(false, false) {
30 target_thread->PostTask(FROM_HERE,
31 base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd));
32 }
33
dchengfe61fca2014-10-22 02:29:5234 ~SocketAcceptor() override {
dchengf3076af2014-10-21 18:02:4235 Close();
36 }
[email protected]bdf9bdc2013-03-13 04:23:1037
38 int server_fd() const { return server_fd_; }
39
40 void WaitUntilReady() {
41 started_watching_event_.Wait();
42 }
43
44 void WaitForAccept() {
45 accepted_event_.Wait();
46 }
47
48 void Close() {
49 if (watcher_.get()) {
50 target_thread_->PostTask(FROM_HERE,
51 base::Bind(&SocketAcceptor::StopWatching, base::Unretained(this),
52 watcher_.release()));
53 }
54 }
55
56 private:
57 void StartWatching(int fd) {
[email protected]fd0a773a2013-04-30 20:55:0358 watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
59 base::MessageLoopForIO::current()->WatchFileDescriptor(
60 fd, true, base::MessageLoopForIO::WATCH_READ, watcher_.get(), this);
[email protected]bdf9bdc2013-03-13 04:23:1061 started_watching_event_.Signal();
62 }
[email protected]fd0a773a2013-04-30 20:55:0363 void StopWatching(base::MessageLoopForIO::FileDescriptorWatcher* watcher) {
[email protected]bdf9bdc2013-03-13 04:23:1064 watcher->StopWatchingFileDescriptor();
65 delete watcher;
66 }
dchengfe61fca2014-10-22 02:29:5267 void OnFileCanReadWithoutBlocking(int fd) override {
[email protected]bdf9bdc2013-03-13 04:23:1068 ASSERT_EQ(-1, server_fd_);
69 IPC::ServerAcceptConnection(fd, &server_fd_);
70 watcher_->StopWatchingFileDescriptor();
71 accepted_event_.Signal();
72 }
dchengfe61fca2014-10-22 02:29:5273 void OnFileCanWriteWithoutBlocking(int fd) override {}
[email protected]bdf9bdc2013-03-13 04:23:1074
75 int server_fd_;
skyostile687bdff2015-05-12 11:29:2176 base::SingleThreadTaskRunner* target_thread_;
[email protected]fd0a773a2013-04-30 20:55:0377 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> watcher_;
[email protected]bdf9bdc2013-03-13 04:23:1078 base::WaitableEvent started_watching_event_;
79 base::WaitableEvent accepted_event_;
80
81 DISALLOW_COPY_AND_ASSIGN(SocketAcceptor);
82};
83
84const base::FilePath GetChannelDir() {
[email protected]bdf9bdc2013-03-13 04:23:1085 base::FilePath tmp_dir;
byungchule2295eb2015-01-22 17:43:5986 PathService::Get(base::DIR_TEMP, &tmp_dir);
[email protected]bdf9bdc2013-03-13 04:23:1087 return tmp_dir;
[email protected]bdf9bdc2013-03-13 04:23:1088}
89
90class TestUnixSocketConnection {
91 public:
92 TestUnixSocketConnection()
93 : worker_("WorkerThread"),
94 server_listen_fd_(-1),
95 server_fd_(-1),
96 client_fd_(-1) {
97 socket_name_ = GetChannelDir().Append("TestSocket");
98 base::Thread::Options options;
[email protected]fd0a773a2013-04-30 20:55:0399 options.message_loop_type = base::MessageLoop::TYPE_IO;
[email protected]bdf9bdc2013-03-13 04:23:10100 worker_.StartWithOptions(options);
101 }
102
103 bool CreateServerSocket() {
104 IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_);
105 if (server_listen_fd_ < 0)
106 return false;
107 struct stat socket_stat;
108 stat(socket_name_.value().c_str(), &socket_stat);
109 EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode));
skyostile687bdff2015-05-12 11:29:21110 acceptor_.reset(
111 new SocketAcceptor(server_listen_fd_, worker_.task_runner().get()));
[email protected]bdf9bdc2013-03-13 04:23:10112 acceptor_->WaitUntilReady();
113 return true;
114 }
115
116 bool CreateClientSocket() {
117 DCHECK(server_listen_fd_ >= 0);
118 IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_);
119 if (client_fd_ < 0)
120 return false;
121 acceptor_->WaitForAccept();
122 server_fd_ = acceptor_->server_fd();
123 return server_fd_ >= 0;
124 }
125
126 virtual ~TestUnixSocketConnection() {
127 if (client_fd_ >= 0)
128 close(client_fd_);
129 if (server_fd_ >= 0)
130 close(server_fd_);
131 if (server_listen_fd_ >= 0) {
132 close(server_listen_fd_);
133 unlink(socket_name_.value().c_str());
134 }
135 }
136
137 int client_fd() const { return client_fd_; }
138 int server_fd() const { return server_fd_; }
139
140 private:
141 base::Thread worker_;
142 base::FilePath socket_name_;
143 int server_listen_fd_;
144 int server_fd_;
145 int client_fd_;
146 scoped_ptr<SocketAcceptor> acceptor_;
147};
148
149// Ensure that IPC::CreateServerUnixDomainSocket creates a socket that
150// IPC::CreateClientUnixDomainSocket can successfully connect to.
151TEST(UnixDomainSocketUtil, Connect) {
152 TestUnixSocketConnection connection;
153 ASSERT_TRUE(connection.CreateServerSocket());
154 ASSERT_TRUE(connection.CreateClientSocket());
155}
156
157// Ensure that messages can be sent across the resulting socket.
158TEST(UnixDomainSocketUtil, SendReceive) {
159 TestUnixSocketConnection connection;
160 ASSERT_TRUE(connection.CreateServerSocket());
161 ASSERT_TRUE(connection.CreateClientSocket());
162
163 const char buffer[] = "Hello, server!";
164 size_t buf_len = sizeof(buffer);
165 size_t sent_bytes =
166 HANDLE_EINTR(send(connection.client_fd(), buffer, buf_len, 0));
167 ASSERT_EQ(buf_len, sent_bytes);
168 char recv_buf[sizeof(buffer)];
169 size_t received_bytes =
170 HANDLE_EINTR(recv(connection.server_fd(), recv_buf, buf_len, 0));
171 ASSERT_EQ(buf_len, received_bytes);
172 ASSERT_EQ(0, memcmp(recv_buf, buffer, buf_len));
173}
174
175} // namespace