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