12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/socket.h> 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h" 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/posix/eintr_wrapper.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/unix_domain_socket_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class SocketAcceptor : public base::MessageLoopForIO::Watcher { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketAcceptor(int fd, base::MessageLoopProxy* target_thread) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : server_fd_(-1), 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) target_thread_(target_thread), 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) started_watching_event_(false, false), 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) accepted_event_(false, false) { 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) target_thread->PostTask(FROM_HERE, 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SocketAcceptor::StartWatching, base::Unretained(this), fd)); 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~SocketAcceptor() { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int server_fd() const { return server_fd_; } 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void WaitUntilReady() { 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) started_watching_event_.Wait(); 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void WaitForAccept() { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) accepted_event_.Wait(); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void Close() { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (watcher_.get()) { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) target_thread_->PostTask(FROM_HERE, 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&SocketAcceptor::StopWatching, base::Unretained(this), 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) watcher_.release())); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void StartWatching(int fd) { 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher); 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoopForIO::current()->WatchFileDescriptor( 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fd, true, base::MessageLoopForIO::WATCH_READ, watcher_.get(), this); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) started_watching_event_.Signal(); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void StopWatching(base::MessageLoopForIO::FileDescriptorWatcher* watcher) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) watcher->StopWatchingFileDescriptor(); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete watcher; 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(-1, server_fd_); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::ServerAcceptConnection(fd, &server_fd_); 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) watcher_->StopWatchingFileDescriptor(); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) accepted_event_.Signal(); 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int server_fd_; 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::MessageLoopProxy* target_thread_; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> watcher_; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WaitableEvent started_watching_event_; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WaitableEvent accepted_event_; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(SocketAcceptor); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath GetChannelDir() { 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_ANDROID) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath tmp_dir; 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PathService::Get(base::DIR_CACHE, &tmp_dir); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return tmp_dir; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath("/var/tmp"); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestUnixSocketConnection { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestUnixSocketConnection() 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : worker_("WorkerThread"), 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server_listen_fd_(-1), 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server_fd_(-1), 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_fd_(-1) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_name_ = GetChannelDir().Append("TestSocket"); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Thread::Options options; 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) options.message_loop_type = base::MessageLoop::TYPE_IO; 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) worker_.StartWithOptions(options); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool CreateServerSocket() { 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::CreateServerUnixDomainSocket(socket_name_, &server_listen_fd_); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (server_listen_fd_ < 0) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct stat socket_stat; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stat(socket_name_.value().c_str(), &socket_stat); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(S_ISSOCK(socket_stat.st_mode)); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) acceptor_.reset(new SocketAcceptor(server_listen_fd_, 1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) worker_.message_loop_proxy().get())); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) acceptor_->WaitUntilReady(); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool CreateClientSocket() { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(server_listen_fd_ >= 0); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::CreateClientUnixDomainSocket(socket_name_, &client_fd_); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (client_fd_ < 0) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) acceptor_->WaitForAccept(); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) server_fd_ = acceptor_->server_fd(); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return server_fd_ >= 0; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~TestUnixSocketConnection() { 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (client_fd_ >= 0) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close(client_fd_); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (server_fd_ >= 0) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close(server_fd_); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (server_listen_fd_ >= 0) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close(server_listen_fd_); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unlink(socket_name_.value().c_str()); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int client_fd() const { return client_fd_; } 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int server_fd() const { return server_fd_; } 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Thread worker_; 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath socket_name_; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int server_listen_fd_; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int server_fd_; 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int client_fd_; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<SocketAcceptor> acceptor_; 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Ensure that IPC::CreateServerUnixDomainSocket creates a socket that 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// IPC::CreateClientUnixDomainSocket can successfully connect to. 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(UnixDomainSocketUtil, Connect) { 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestUnixSocketConnection connection; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(connection.CreateServerSocket()); 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(connection.CreateClientSocket()); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Ensure that messages can be sent across the resulting socket. 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(UnixDomainSocketUtil, SendReceive) { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TestUnixSocketConnection connection; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(connection.CreateServerSocket()); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(connection.CreateClientSocket()); 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char buffer[] = "Hello, server!"; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t buf_len = sizeof(buffer); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t sent_bytes = 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HANDLE_EINTR(send(connection.client_fd(), buffer, buf_len, 0)); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(buf_len, sent_bytes); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char recv_buf[sizeof(buffer)]; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t received_bytes = 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HANDLE_EINTR(recv(connection.server_fd(), recv_buf, buf_len, 0)); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(buf_len, received_bytes); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_EQ(0, memcmp(recv_buf, buffer, buf_len)); 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 176