summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-08 08:06:35 +0000
committerjeremya@chromium.org <jeremya@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-08 08:06:35 +0000
commit126ced008aafdd311fab8706d53e609b425a6510 (patch)
treef684eb5cdc667552b9a5f6715c9bb5ae592f6e1b
parent092d16cda988000df298a04590b84d6ebb73fac9 (diff)
downloadchromium_src-126ced008aafdd311fab8706d53e609b425a6510.zip
chromium_src-126ced008aafdd311fab8706d53e609b425a6510.tar.gz
chromium_src-126ced008aafdd311fab8706d53e609b425a6510.tar.bz2
Revert 186912
> 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. > > Review URL: https://codereview.chromium.org/12386010 TBR=jeremya@chromium.org Review URL: https://codereview.chromium.org/12510008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@186919 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ipc/ipc.gyp6
-rw-r--r--ipc/ipc.gypi14
-rw-r--r--ipc/ipc_channel.h4
-rw-r--r--ipc/ipc_channel_factory.cc88
-rw-r--r--ipc/ipc_channel_factory.h57
-rw-r--r--ipc/ipc_channel_posix.cc189
-rw-r--r--ipc/ipc_channel_posix.h8
-rw-r--r--ipc/ipc_channel_posix_unittest.cc5
-rw-r--r--ipc/ipc_channel_proxy.cc4
-rw-r--r--ipc/ipc_channel_proxy.h2
-rw-r--r--ipc/unix_domain_socket_util.cc202
-rw-r--r--ipc/unix_domain_socket_util.h64
-rw-r--r--ipc/unix_domain_socket_util_unittest.cc163
13 files changed, 185 insertions, 621 deletions
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp
index a247651..5e2f3a7 100644
--- a/ipc/ipc.gyp
+++ b/ipc/ipc.gyp
@@ -58,7 +58,6 @@
'ipc_test_base.cc',
'ipc_test_base.h',
'sync_socket_unittest.cc',
- 'unix_domain_socket_util_unittest.cc',
],
'conditions': [
['toolkit_uses_gtk == 1', {
@@ -66,11 +65,6 @@
'../build/linux/system.gyp:gtk',
],
}],
- ['OS == "win" or OS == "ios"', {
- 'sources!': [
- 'unix_domain_socket_util_unittest.cc',
- ],
- }],
['OS == "android" and gtest_target_type == "shared_library"', {
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
diff --git a/ipc/ipc.gypi b/ipc/ipc.gypi
index ba80e42..ef986a7 100644
--- a/ipc/ipc.gypi
+++ b/ipc/ipc.gypi
@@ -13,10 +13,8 @@
'sources': [
'file_descriptor_set_posix.cc',
'file_descriptor_set_posix.h',
- 'ipc_channel.cc',
'ipc_channel.h',
- 'ipc_channel_factory.cc',
- 'ipc_channel_factory.h',
+ 'ipc_channel.cc',
'ipc_channel_handle.h',
'ipc_channel_nacl.cc',
'ipc_channel_nacl.h',
@@ -59,8 +57,6 @@
'param_traits_write_macros.h',
'struct_constructor_macros.h',
'struct_destructor_macros.h',
- 'unix_domain_socket_util.cc',
- 'unix_domain_socket_util.h',
],
'defines': [
'IPC_IMPLEMENTATION',
@@ -72,15 +68,7 @@
['>(nacl_untrusted_build)==1', {
'sources!': [
'ipc_channel.cc',
- 'ipc_channel_factory.cc',
'ipc_channel_posix.cc',
- 'unix_domain_socket_util.cc',
- ],
- }],
- ['OS == "win" or OS == "ios"', {
- 'sources!': [
- 'ipc_channel_factory.cc',
- 'unix_domain_socket_util.cc',
],
}],
],
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
index 35ead53..29caec3 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -167,8 +167,8 @@ class IPC_EXPORT Channel : public Sender {
bool HasAcceptedConnection() const;
// Returns true if the peer process' effective user id can be determined, in
- // which case the supplied peer_euid is updated with it.
- bool GetPeerEuid(uid_t* peer_euid) const;
+ // which case the supplied client_euid is updated with it.
+ bool GetClientEuid(uid_t* client_euid) const;
// Closes any currently connected socket, and returns to a listening state
// for more connections.
diff --git a/ipc/ipc_channel_factory.cc b/ipc/ipc_channel_factory.cc
deleted file mode 100644
index d355328..0000000
--- a/ipc/ipc_channel_factory.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 "ipc/ipc_channel_factory.h"
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "ipc/unix_domain_socket_util.h"
-
-namespace IPC {
-
-ChannelFactory::ChannelFactory(const base::FilePath& path, Delegate* delegate)
- : path_(path), delegate_(delegate), listen_fd_(-1) {
- DCHECK(delegate_);
- CreateSocket();
-}
-
-ChannelFactory::~ChannelFactory() {
- Close();
-}
-
-bool ChannelFactory::CreateSocket() {
- DCHECK(listen_fd_ < 0);
-
- // Create the socket.
- return CreateServerUnixDomainSocket(path_, &listen_fd_);
-}
-
-bool ChannelFactory::Listen() {
- if (listen_fd_ < 0)
- return false;
-
- // Watch the fd for connections, and turn any connections into
- // active sockets.
- MessageLoopForIO::current()->WatchFileDescriptor(
- listen_fd_,
- true,
- MessageLoopForIO::WATCH_READ,
- &server_listen_connection_watcher_,
- this);
- return true;
-}
-
-// Called by libevent when we can read from the fd without blocking.
-void ChannelFactory::OnFileCanReadWithoutBlocking(int fd) {
- DCHECK(fd == listen_fd_);
- int new_fd = -1;
- if (!ServerAcceptConnection(listen_fd_, &new_fd)) {
- Close();
- delegate_->OnListenError();
- return;
- }
-
- if (new_fd < 0) {
- // The accept() failed, but not in such a way that the factory needs to be
- // shut down.
- return;
- }
-
- file_util::ScopedFD scoped_fd(&new_fd);
-
- // Verify that the IPC channel peer is running as the same user.
- if (!IsPeerAuthorized(new_fd))
- return;
-
- ChannelHandle handle("", base::FileDescriptor(*scoped_fd.release(), true));
- delegate_->OnClientConnected(handle);
-}
-
-void ChannelFactory::OnFileCanWriteWithoutBlocking(int fd) {
- NOTREACHED() << "Listen fd should never be writable.";
-}
-
-void ChannelFactory::Close() {
- if (listen_fd_ < 0)
- return;
- if (HANDLE_EINTR(close(listen_fd_)) < 0)
- PLOG(ERROR) << "close";
- listen_fd_ = -1;
- if (unlink(path_.value().c_str()) < 0)
- PLOG(ERROR) << "unlink";
-
- // Unregister libevent for the listening socket and close it.
- server_listen_connection_watcher_.StopWatchingFileDescriptor();
-}
-
-} // namespace IPC
diff --git a/ipc/ipc_channel_factory.h b/ipc/ipc_channel_factory.h
deleted file mode 100644
index a1e1d85..0000000
--- a/ipc/ipc_channel_factory.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#ifndef IPC_IPC_CHANNEL_FACTORY_H_
-#define IPC_IPC_CHANNEL_FACTORY_H_
-
-#include "base/files/file_path.h"
-#include "base/message_loop.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_export.h"
-
-namespace IPC {
-
-// A ChannelFactory listens on a UNIX domain socket. When a client connects to
-// the socket, it accept()s the connection and passes the new FD to the
-// delegate. The delegate is then responsible for creating a new IPC::Channel
-// for the FD.
-class IPC_EXPORT ChannelFactory : public MessageLoopForIO::Watcher {
- public:
- class Delegate {
- public:
- // Called when a client connects to the factory. It is the delegate's
- // responsibility to create an IPC::Channel for the handle, or else close
- // the file descriptor contained therein.
- virtual void OnClientConnected(const ChannelHandle& handle) = 0;
-
- // Called when an error occurs and the channel is closed.
- virtual void OnListenError() = 0;
- };
-
- ChannelFactory(const base::FilePath& path, Delegate* delegate);
-
- virtual ~ChannelFactory();
-
- // Call this to start listening on the socket.
- bool Listen();
-
- // Close and unlink the socket, and stop accepting connections.
- void Close();
-
- private:
- bool CreateSocket();
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
-
- MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_;
- base::FilePath path_;
- Delegate* delegate_;
- int listen_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(ChannelFactory);
-};
-
-} // namespace IPC
-
-#endif // IPC_IPC_CHANNEL_FACTORY_H_
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index 6aaac49..17b3641 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -40,7 +40,6 @@
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_switches.h"
-#include "ipc/unix_domain_socket_util.h"
namespace IPC {
@@ -138,6 +137,143 @@ class PipeMap {
};
//------------------------------------------------------------------------------
+// Verify that kMaxPipeNameLength is a decent size.
+COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxPipeNameLength,
+ BAD_SUN_PATH_LENGTH);
+
+// Creates a unix domain socket bound to the specified name that is listening
+// for connections.
+bool CreateServerUnixDomainSocket(const std::string& pipe_name,
+ int* server_listen_fd) {
+ DCHECK(server_listen_fd);
+
+ if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
+ DLOG(ERROR) << "pipe_name.length() == " << pipe_name.length();
+ return false;
+ }
+
+ // Create socket.
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return false;
+ }
+
+ // Make socket non-blocking
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Delete any old FS instances.
+ unlink(pipe_name.c_str());
+
+ // Make sure the path we need exists.
+ base::FilePath path(pipe_name);
+ base::FilePath dir_path = path.DirName();
+ if (!file_util::CreateDirectory(dir_path)) {
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Create unix_addr structure.
+ struct sockaddr_un unix_addr;
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ int path_len = snprintf(unix_addr.sun_path, IPC::kMaxPipeNameLength,
+ "%s", pipe_name.c_str());
+ DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
+ size_t unix_addr_len = offsetof(struct sockaddr_un,
+ sun_path) + path_len + 1;
+
+ // Bind the socket.
+ if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
+ unix_addr_len) != 0) {
+ PLOG(ERROR) << "bind " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Start listening on the socket.
+ const int listen_queue_length = 1;
+ if (listen(fd, listen_queue_length) != 0) {
+ PLOG(ERROR) << "listen " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ *server_listen_fd = fd;
+ return true;
+}
+
+// Accept a connection on a socket we are listening to.
+bool ServerAcceptConnection(int server_listen_fd, int* server_socket) {
+ DCHECK(server_socket);
+
+ int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
+ if (accept_fd < 0)
+ return false;
+ if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd;
+ if (HANDLE_EINTR(close(accept_fd)) < 0)
+ PLOG(ERROR) << "close " << accept_fd;
+ return false;
+ }
+
+ *server_socket = accept_fd;
+ return true;
+}
+
+bool CreateClientUnixDomainSocket(const std::string& pipe_name,
+ int* client_socket) {
+ DCHECK(client_socket);
+ DCHECK_GT(pipe_name.length(), 0u);
+ DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
+
+ if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
+ return false;
+ }
+
+ // Create socket.
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ PLOG(ERROR) << "socket " << pipe_name;
+ return false;
+ }
+
+ // Make socket non-blocking
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Create server side of socket.
+ struct sockaddr_un server_unix_addr;
+ memset(&server_unix_addr, 0, sizeof(server_unix_addr));
+ server_unix_addr.sun_family = AF_UNIX;
+ int path_len = snprintf(server_unix_addr.sun_path, IPC::kMaxPipeNameLength,
+ "%s", pipe_name.c_str());
+ DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
+ size_t server_unix_addr_len = offsetof(struct sockaddr_un,
+ sun_path) + path_len + 1;
+
+ if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
+ server_unix_addr_len)) != 0) {
+ PLOG(ERROR) << "connect " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ *client_socket = fd;
+ return true;
+}
bool SocketWriteErrorIsRecoverable() {
#if defined(OS_MACOSX)
@@ -252,20 +388,12 @@ bool Channel::ChannelImpl::CreatePipe(
} else if (mode_ & MODE_NAMED_FLAG) {
// Case 2 from comment above.
if (mode_ & MODE_SERVER_FLAG) {
- if (!CreateServerUnixDomainSocket(base::FilePath(pipe_name_),
- &local_pipe)) {
+ if (!CreateServerUnixDomainSocket(pipe_name_, &local_pipe)) {
return false;
}
must_unlink_ = true;
} else if (mode_ & MODE_CLIENT_FLAG) {
- if (!CreateClientUnixDomainSocket(base::FilePath(pipe_name_),
- &local_pipe)) {
- return false;
- }
- // Verify that the server has the same euid as the client.
- if (!IPC::IsPeerAuthorized(local_pipe)) {
- if (HANDLE_EINTR(close(local_pipe)) < 0)
- PLOG(ERROR) << "close " << pipe_name_;
+ if (!CreateClientUnixDomainSocket(pipe_name_, &local_pipe)) {
return false;
}
} else {
@@ -546,9 +674,33 @@ bool Channel::ChannelImpl::HasAcceptedConnection() const {
return AcceptsConnections() && pipe_ != -1;
}
-bool Channel::ChannelImpl::GetPeerEuid(uid_t* peer_euid) const {
- DCHECK(!(mode_ & MODE_SERVER) || HasAcceptedConnection());
- return IPC::GetPeerEuid(pipe_, peer_euid);
+bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const {
+ DCHECK(HasAcceptedConnection());
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+ uid_t peer_euid;
+ gid_t peer_gid;
+ if (getpeereid(pipe_, &peer_euid, &peer_gid) != 0) {
+ PLOG(ERROR) << "getpeereid " << pipe_;
+ return false;
+ }
+ *client_euid = peer_euid;
+ return true;
+#elif defined(OS_SOLARIS)
+ return false;
+#else
+ struct ucred cred;
+ socklen_t cred_len = sizeof(cred);
+ if (getsockopt(pipe_, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != 0) {
+ PLOG(ERROR) << "getsockopt " << pipe_;
+ return false;
+ }
+ if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
+ NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
+ return false;
+ }
+ *client_euid = cred.uid;
+ return true;
+#endif
}
void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
@@ -601,8 +753,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
bool send_server_hello_msg = false;
if (fd == server_listen_pipe_) {
int new_pipe = 0;
- if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) ||
- new_pipe < 0) {
+ if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe)) {
Close();
listener()->OnChannelListenError();
}
@@ -622,7 +773,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) {
// Verify that the IPC channel peer is running as the same user.
uid_t client_euid;
- if (!GetPeerEuid(&client_euid)) {
+ if (!GetClientEuid(&client_euid)) {
DLOG(ERROR) << "Unable to query client euid";
ResetToAcceptingConnectionState();
return;
@@ -1006,8 +1157,8 @@ bool Channel::HasAcceptedConnection() const {
return channel_impl_->HasAcceptedConnection();
}
-bool Channel::GetPeerEuid(uid_t* peer_euid) const {
- return channel_impl_->GetPeerEuid(peer_euid);
+bool Channel::GetClientEuid(uid_t* client_euid) const {
+ return channel_impl_->GetClientEuid(client_euid);
}
void Channel::ResetToAcceptingConnectionState() {
diff --git a/ipc/ipc_channel_posix.h b/ipc/ipc_channel_posix.h
index 6378c33..38e14ef 100644
--- a/ipc/ipc_channel_posix.h
+++ b/ipc/ipc_channel_posix.h
@@ -63,7 +63,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
void CloseClientFileDescriptor();
bool AcceptsConnections() const;
bool HasAcceptedConnection() const;
- bool GetPeerEuid(uid_t* peer_euid) const;
+ bool GetClientEuid(uid_t* client_euid) const;
void ResetToAcceptingConnectionState();
base::ProcessId peer_pid() const { return peer_pid_; }
static bool IsNamedServerInitialized(const std::string& channel_id);
@@ -194,6 +194,12 @@ class Channel::ChannelImpl : public internal::ChannelReader,
DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
};
+// The maximum length of the name of a pipe for MODE_NAMED_SERVER or
+// MODE_NAMED_CLIENT if you want to pass in your own socket.
+// The standard size on linux is 108, mac is 104. To maintain consistency
+// across platforms we standardize on the smaller value.
+static const size_t kMaxPipeNameLength = 104;
+
} // namespace IPC
#endif // IPC_IPC_CHANNEL_POSIX_H_
diff --git a/ipc/ipc_channel_posix_unittest.cc b/ipc/ipc_channel_posix_unittest.cc
index b49b096..448e648 100644
--- a/ipc/ipc_channel_posix_unittest.cc
+++ b/ipc/ipc_channel_posix_unittest.cc
@@ -21,7 +21,6 @@
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "ipc/ipc_listener.h"
-#include "ipc/unix_domain_socket_util.h"
#include "testing/multiprocess_func_list.h"
namespace {
@@ -146,7 +145,7 @@ void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle,
struct sockaddr_un server_address = { 0 };
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
- int path_len = snprintf(server_address.sun_path, IPC::kMaxSocketNameLength,
+ int path_len = snprintf(server_address.sun_path, IPC::kMaxPipeNameLength,
"%s", name.c_str());
DCHECK_EQ(static_cast<int>(name.length()), path_len);
size_t server_address_len = offsetof(struct sockaddr_un,
@@ -312,7 +311,7 @@ TEST_F(IPCChannelPosixTest, BadChannelName) {
"future-proof_growth_strategies_Continually"
"pontificate_proactive_potentialities_before"
"leading-edge_processes";
- EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength);
+ EXPECT_GE(strlen(kTooLongName), IPC::kMaxPipeNameLength);
IPC::ChannelHandle handle2(kTooLongName);
IPC::Channel channel2(handle2, IPC::Channel::MODE_NAMED_SERVER, NULL);
EXPECT_FALSE(channel2.Connect());
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
index 1048310..0202e9e 100644
--- a/ipc/ipc_channel_proxy.cc
+++ b/ipc/ipc_channel_proxy.cc
@@ -414,13 +414,13 @@ int ChannelProxy::TakeClientFileDescriptor() {
return channel->TakeClientFileDescriptor();
}
-bool ChannelProxy::GetPeerEuid(uid_t* peer_euid) const {
+bool ChannelProxy::GetClientEuid(uid_t* client_euid) const {
DCHECK(CalledOnValidThread());
Channel* channel = context_.get()->channel_.get();
// Channel must have been created first.
DCHECK(channel) << context_.get()->channel_id_;
- return channel->GetPeerEuid(peer_euid);
+ return channel->GetClientEuid(client_euid);
}
#endif
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h
index 6fbbc2a..e4cd83a 100644
--- a/ipc/ipc_channel_proxy.h
+++ b/ipc/ipc_channel_proxy.h
@@ -181,7 +181,7 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// Calls through to the underlying channel's methods.
int GetClientFileDescriptor();
int TakeClientFileDescriptor();
- bool GetPeerEuid(uid_t* peer_euid) const;
+ bool GetClientEuid(uid_t* client_euid) const;
#endif // defined(OS_POSIX)
protected:
diff --git a/ipc/unix_domain_socket_util.cc b/ipc/unix_domain_socket_util.cc
deleted file mode 100644
index 7f513a3..0000000
--- a/ipc/unix_domain_socket_util.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// 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 "ipc/unix_domain_socket_util.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-
-namespace IPC {
-
-// Verify that kMaxSocketNameLength is a decent size.
-COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength,
- BAD_SUN_PATH_LENGTH);
-
-namespace {
-
-// Returns fd (>= 0) on success, -1 on failure. If successful, fills in
-// |unix_addr| with the appropriate data for the socket, and sets
-// |unix_addr_len| to the length of the data therein.
-int MakeUnixAddrForPath(const std::string& socket_name,
- struct sockaddr_un* unix_addr,
- size_t* unix_addr_len) {
- DCHECK(unix_addr);
- DCHECK(unix_addr_len);
-
- if (socket_name.length() == 0) {
- LOG(ERROR) << "Empty socket name provided for unix socket address.";
- return -1;
- }
- // We reject socket_name.length() == kMaxSocketNameLength to make room for
- // the NUL terminator at the end of the string.
- if (socket_name.length() >= kMaxSocketNameLength) {
- LOG(ERROR) << "Socket name too long: " << socket_name;
- return -1;
- }
-
- // Create socket.
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- PLOG(ERROR) << "socket";
- return -1;
- }
- file_util::ScopedFD scoped_fd(&fd);
-
- // Make socket non-blocking
- if (HANDLE_EINTR(fcntl(fd, F_SETFL, O_NONBLOCK)) < 0) {
- PLOG(ERROR) << "fcntl(O_NONBLOCK)";
- return -1;
- }
-
- // Create unix_addr structure.
- memset(unix_addr, 0, sizeof(struct sockaddr_un));
- unix_addr->sun_family = AF_UNIX;
- strncpy(unix_addr->sun_path, socket_name.c_str(), kMaxSocketNameLength);
- *unix_addr_len =
- offsetof(struct sockaddr_un, sun_path) + socket_name.length();
- return *scoped_fd.release();
-}
-
-} // namespace
-
-bool CreateServerUnixDomainSocket(const base::FilePath& socket_path,
- int* server_listen_fd) {
- DCHECK(server_listen_fd);
-
- std::string socket_name = socket_path.value();
- base::FilePath socket_dir = socket_path.DirName();
-
- struct sockaddr_un unix_addr;
- size_t unix_addr_len;
- int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len);
- if (fd < 0)
- return false;
- file_util::ScopedFD scoped_fd(&fd);
-
- // Make sure the path we need exists.
- if (!file_util::CreateDirectory(socket_dir)) {
- LOG(ERROR) << "Couldn't create directory: " << socket_dir.value();
- return false;
- }
-
- // Delete any old FS instances.
- if (unlink(socket_name.c_str()) < 0 && errno != ENOENT) {
- PLOG(ERROR) << "unlink " << socket_name;
- return false;
- }
-
- // Bind the socket.
- if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
- unix_addr_len) < 0) {
- PLOG(ERROR) << "bind " << socket_path.value();
- return false;
- }
-
- // Start listening on the socket.
- if (listen(fd, SOMAXCONN) < 0) {
- PLOG(ERROR) << "listen " << socket_path.value();
- unlink(socket_name.c_str());
- return false;
- }
-
- *server_listen_fd = *scoped_fd.release();
- return true;
-}
-
-bool CreateClientUnixDomainSocket(const base::FilePath& socket_path,
- int* client_socket) {
- DCHECK(client_socket);
-
- std::string socket_name = socket_path.value();
- base::FilePath socket_dir = socket_path.DirName();
-
- struct sockaddr_un unix_addr;
- size_t unix_addr_len;
- int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len);
- if (fd < 0)
- return false;
- file_util::ScopedFD scoped_fd(&fd);
-
- if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&unix_addr),
- unix_addr_len)) < 0) {
- PLOG(ERROR) << "connect " << socket_path.value();
- return false;
- }
-
- *client_socket = *scoped_fd.release();
- return true;
-}
-
-bool GetPeerEuid(int fd, uid_t* peer_euid) {
- DCHECK(peer_euid);
-#if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD)
- uid_t socket_euid;
- gid_t socket_gid;
- if (getpeereid(fd, &socket_euid, &socket_gid) < 0) {
- PLOG(ERROR) << "getpeereid " << fd;
- return false;
- }
- *peer_euid = socket_euid;
- return true;
-#else
- struct ucred cred;
- socklen_t cred_len = sizeof(cred);
- if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) < 0) {
- PLOG(ERROR) << "getsockopt " << fd;
- return false;
- }
- if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
- NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
- return false;
- }
- *peer_euid = cred.uid;
- return true;
-#endif
-}
-
-bool IsPeerAuthorized(int peer_fd) {
- uid_t peer_euid;
- if (!GetPeerEuid(peer_fd, &peer_euid))
- return false;
- if (peer_euid != geteuid()) {
- DLOG(ERROR) << "Client euid is not authorised";
- return false;
- }
- return true;
-}
-
-bool IsRecoverableError(int err) {
- return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE ||
- errno == ENOMEM || errno == ENOBUFS;
-}
-
-bool ServerAcceptConnection(int server_listen_fd, int* server_socket) {
- DCHECK(server_socket);
- *server_socket = -1;
-
- int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
- if (accept_fd < 0)
- return IsRecoverableError(errno);
- file_util::ScopedFD scoped_fd(&accept_fd);
- if (HANDLE_EINTR(fcntl(accept_fd, F_SETFL, O_NONBLOCK)) < 0) {
- PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd;
- // It's safe to keep listening on |server_listen_fd| even if the attempt to
- // set O_NONBLOCK failed on the client fd.
- return true;
- }
-
- *server_socket = *scoped_fd.release();
- return true;
-}
-
-} // namespace IPC
diff --git a/ipc/unix_domain_socket_util.h b/ipc/unix_domain_socket_util.h
deleted file mode 100644
index 5752364..0000000
--- a/ipc/unix_domain_socket_util.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-#ifndef IPC_UNIX_DOMAIN_SOCKET_UTIL_H_
-#define IPC_UNIX_DOMAIN_SOCKET_UTIL_H_
-
-#include <sys/types.h>
-
-#include <string>
-
-#include "ipc/ipc_export.h"
-
-namespace base {
-class FilePath;
-} // namespace base
-
-namespace IPC {
-
-// Creates a UNIX-domain socket at |socket_name| and bind()s it, then listen()s
-// on it. If successful, |server_listen_fd| will be set to the new file
-// descriptor, and the function will return true. Otherwise returns false.
-//
-// This function also effectively performs `mkdir -p` on the dirname of
-// |socket_name| to ensure that all the directories up to |socket_name| exist.
-// As a result of which this function must be run on a thread that allows
-// blocking I/O, e.g. the FILE thread in Chrome's browser process.
-IPC_EXPORT bool CreateServerUnixDomainSocket(const base::FilePath& socket_name,
- int* server_listen_fd);
-
-// Opens a UNIX-domain socket at |socket_name| and connect()s to it. If
-// successful, |client_socket| will be set to the new file descriptor, and the
-// function will return true. Otherwise returns false.
-IPC_EXPORT bool CreateClientUnixDomainSocket(const base::FilePath& socket_name,
- int* client_socket);
-
-// Gets the effective user ID of the other end of the UNIX-domain socket
-// specified by |fd|. If successful, sets |peer_euid| to the uid, and returns
-// true. Otherwise returns false.
-IPC_EXPORT bool GetPeerEuid(int fd, uid_t* peer_euid);
-
-// Checks that the process on the other end of the UNIX domain socket
-// represented by |peer_fd| shares the same EUID as this process.
-IPC_EXPORT bool IsPeerAuthorized(int peer_fd);
-
-// Accepts a client attempting to connect to |server_listen_fd|, storing the
-// new file descriptor for the connection in |server_socket|.
-//
-// Returns false if |server_listen_fd| encounters an unrecoverable error.
-// Returns true if it's valid to keep listening on |server_listen_fd|. In this
-// case, it's possible that a connection wasn't successfully established; then,
-// |server_socket| will be set to -1.
-IPC_EXPORT bool ServerAcceptConnection(int server_listen_fd,
- int* server_socket);
-
-// The maximum length of the name of a socket for MODE_NAMED_SERVER or
-// MODE_NAMED_CLIENT if you want to pass in your own socket.
-// The standard size on linux is 108, mac is 104. To maintain consistency
-// across platforms we standardize on the smaller value.
-static const size_t kMaxSocketNameLength = 104;
-
-} // namespace IPC
-
-#endif // IPC_UNIX_DOMAIN_SOCKET_UTIL_H_
diff --git a/ipc/unix_domain_socket_util_unittest.cc b/ipc/unix_domain_socket_util_unittest.cc
deleted file mode 100644
index 1cf41d3..0000000
--- a/ipc/unix_domain_socket_util_unittest.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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