diff options
author | jeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 10:12:17 +0000 |
---|---|---|
committer | jeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 10:12:17 +0000 |
commit | b2720f159750fd54728b7ec0b9da8baed9ec4a83 (patch) | |
tree | ace46256a7c67de83503a9138e4a06e7020043b2 /ipc/unix_domain_socket_util_unittest.cc | |
parent | 587582e20107766501766cf67b43be491de5ed83 (diff) | |
download | chromium_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.cc | 163 |
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 |