summaryrefslogtreecommitdiffstats
path: root/ipc/unix_domain_socket_util_unittest.cc
diff options
context:
space:
mode:
authorjeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 10:12:17 +0000
committerjeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 10:12:17 +0000
commitb2720f159750fd54728b7ec0b9da8baed9ec4a83 (patch)
treeace46256a7c67de83503a9138e4a06e7020043b2 /ipc/unix_domain_socket_util_unittest.cc
parent587582e20107766501766cf67b43be491de5ed83 (diff)
downloadchromium_src-b2720f159750fd54728b7ec0b9da8baed9ec4a83.zip
chromium_src-b2720f159750fd54728b7ec0b9da8baed9ec4a83.tar.gz
chromium_src-b2720f159750fd54728b7ec0b9da8baed9ec4a83.tar.bz2
Implement IPC::ChannelFactory, a class that accept()s on a UNIX socket.
IPC::ChannelFactory listens on a UNIX domain socket and notifies its delegate when a client connects. The delegate is expected to craft an IPC::Channel from the handle it is given. Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=186912 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=187233 Review URL: https://chromiumcodereview.appspot.com/12386010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187554 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ipc/unix_domain_socket_util_unittest.cc')
-rw-r--r--ipc/unix_domain_socket_util_unittest.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/ipc/unix_domain_socket_util_unittest.cc b/ipc/unix_domain_socket_util_unittest.cc
new file mode 100644
index 0000000..1cf41d3
--- /dev/null
+++ b/ipc/unix_domain_socket_util_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/socket.h>
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "ipc/unix_domain_socket_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SocketAcceptor : public MessageLoopForIO::Watcher {
+ public:
+ SocketAcceptor(int fd, base::MessageLoopProxy* target_thread)
+ : server_fd_(-1),
+ started_watching_event_(false, false),
+ accepted_event_(false, false) {
+ target_thread->PostTask(FROM_HERE,
+ base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd));
+ }
+
+ virtual ~SocketAcceptor() {
+ watcher_.StopWatchingFileDescriptor();
+ }
+
+ int server_fd() const { return server_fd_; }
+
+ void WaitUntilReady() {
+ started_watching_event_.Wait();
+ }
+ void WaitForAccept() {
+ accepted_event_.Wait();
+ }
+
+ private:
+ void StartWatching(int fd) {
+ MessageLoopForIO::current()->WatchFileDescriptor(
+ fd,
+ true,
+ MessageLoopForIO::WATCH_READ,
+ &watcher_,
+ this);
+ started_watching_event_.Signal();
+ }
+ virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
+ ASSERT_EQ(-1, server_fd_);
+ IPC::ServerAcceptConnection(fd, &server_fd_);
+ watcher_.StopWatchingFileDescriptor();
+ accepted_event_.Signal();
+ }
+ virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
+
+ int server_fd_;
+ MessageLoopForIO::FileDescriptorWatcher watcher_;
+ base::WaitableEvent started_watching_event_;
+ base::WaitableEvent accepted_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketAcceptor);
+};
+
+const base::FilePath GetChannelDir() {
+#if defined(OS_ANDROID)
+ base::FilePath tmp_dir;
+ PathService::Get(base::DIR_CACHE, &tmp_dir);
+ return tmp_dir;
+#else
+ return base::FilePath("/var/tmp");
+#endif
+}
+
+class TestUnixSocketConnection {
+ public:
+ TestUnixSocketConnection()
+ : worker_("WorkerThread"),
+ server_listen_fd_(-1),
+ server_fd_(-1),
+ client_fd_(-1) {
+ socket_name_ = GetChannelDir().Append("TestSocket");
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ worker_.StartWithOptions(options);
+ }
+
+ bool CreateServerSocket() {
+ IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_);
+ if (server_listen_fd_ < 0)
+ return false;
+ struct stat socket_stat;
+ stat(socket_name_.value().c_str(), &socket_stat);
+ EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode));
+ acceptor_.reset(new SocketAcceptor(server_listen_fd_,
+ worker_.message_loop_proxy()));
+ acceptor_->WaitUntilReady();
+ return true;
+ }
+
+ bool CreateClientSocket() {
+ DCHECK(server_listen_fd_ >= 0);
+ IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_);
+ if (client_fd_ < 0)
+ return false;
+ acceptor_->WaitForAccept();
+ server_fd_ = acceptor_->server_fd();
+ return server_fd_ >= 0;
+ }
+
+ virtual ~TestUnixSocketConnection() {
+ if (client_fd_ >= 0)
+ close(client_fd_);
+ if (server_fd_ >= 0)
+ close(server_fd_);
+ if (server_listen_fd_ >= 0) {
+ close(server_listen_fd_);
+ unlink(socket_name_.value().c_str());
+ }
+ }
+
+ int client_fd() const { return client_fd_; }
+ int server_fd() const { return server_fd_; }
+
+ private:
+ base::Thread worker_;
+ base::FilePath socket_name_;
+ int server_listen_fd_;
+ int server_fd_;
+ int client_fd_;
+ scoped_ptr<SocketAcceptor> acceptor_;
+};
+
+// Ensure that IPC::CreateServerUnixDomainSocket creates a socket that
+// IPC::CreateClientUnixDomainSocket can successfully connect to.
+TEST(UnixDomainSocketUtil, Connect) {
+ TestUnixSocketConnection connection;
+ ASSERT_TRUE(connection.CreateServerSocket());
+ ASSERT_TRUE(connection.CreateClientSocket());
+}
+
+// Ensure that messages can be sent across the resulting socket.
+TEST(UnixDomainSocketUtil, SendReceive) {
+ TestUnixSocketConnection connection;
+ ASSERT_TRUE(connection.CreateServerSocket());
+ ASSERT_TRUE(connection.CreateClientSocket());
+
+ const char buffer[] = "Hello, server!";
+ size_t buf_len = sizeof(buffer);
+ size_t sent_bytes =
+ HANDLE_EINTR(send(connection.client_fd(), buffer, buf_len, 0));
+ ASSERT_EQ(buf_len, sent_bytes);
+ char recv_buf[sizeof(buffer)];
+ size_t received_bytes =
+ HANDLE_EINTR(recv(connection.server_fd(), recv_buf, buf_len, 0));
+ ASSERT_EQ(buf_len, received_bytes);
+ ASSERT_EQ(0, memcmp(recv_buf, buffer, buf_len));
+}
+
+} // namespace