summaryrefslogtreecommitdiff
path: root/mojo/core/platform_handle_in_transit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/core/platform_handle_in_transit.cc')
-rw-r--r--mojo/core/platform_handle_in_transit.cc156
1 files changed, 156 insertions, 0 deletions
diff --git a/mojo/core/platform_handle_in_transit.cc b/mojo/core/platform_handle_in_transit.cc
new file mode 100644
index 0000000000..7b82f27c34
--- /dev/null
+++ b/mojo/core/platform_handle_in_transit.cc
@@ -0,0 +1,156 @@
+// Copyright 2018 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 "mojo/core/platform_handle_in_transit.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace mojo {
+namespace core {
+
+namespace {
+
+#if defined(OS_WIN)
+HANDLE TransferHandle(HANDLE handle,
+ base::ProcessHandle from_process,
+ base::ProcessHandle to_process) {
+ BOOL result =
+ ::DuplicateHandle(from_process, handle, to_process, &handle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ if (result) {
+ return handle;
+ } else {
+ DPLOG(ERROR) << "DuplicateHandle failed";
+ return INVALID_HANDLE_VALUE;
+ }
+}
+
+void CloseHandleInProcess(HANDLE handle, const ScopedProcessHandle& process) {
+ DCHECK_NE(handle, INVALID_HANDLE_VALUE);
+ DCHECK(process.is_valid());
+
+ // The handle lives in |process|, so we close it there using a special
+ // incantation of |DuplicateHandle()|.
+ //
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251 for
+ // this usage of |DuplicateHandle()|, particularly where it says "to close a
+ // handle from the source process...". Note that although the documentation
+ // says that the target *handle* address must be NULL, it seems that the
+ // target process handle being NULL is what really matters here.
+ BOOL result = ::DuplicateHandle(process.get(), handle, NULL, &handle, 0,
+ FALSE, DUPLICATE_CLOSE_SOURCE);
+ if (!result) {
+ DPLOG(ERROR) << "DuplicateHandle failed";
+ }
+}
+#endif
+
+} // namespace
+
+PlatformHandleInTransit::PlatformHandleInTransit() = default;
+
+PlatformHandleInTransit::PlatformHandleInTransit(PlatformHandle handle)
+ : handle_(std::move(handle)) {}
+
+PlatformHandleInTransit::PlatformHandleInTransit(
+ PlatformHandleInTransit&& other) {
+ *this = std::move(other);
+}
+
+PlatformHandleInTransit::~PlatformHandleInTransit() {
+#if defined(OS_WIN)
+ if (!owning_process_.is_valid()) {
+ DCHECK_EQ(remote_handle_, INVALID_HANDLE_VALUE);
+ return;
+ }
+
+ CloseHandleInProcess(remote_handle_, owning_process_);
+#endif
+}
+
+PlatformHandleInTransit& PlatformHandleInTransit::operator=(
+ PlatformHandleInTransit&& other) {
+#if defined(OS_WIN)
+ if (owning_process_.is_valid()) {
+ DCHECK_NE(remote_handle_, INVALID_HANDLE_VALUE);
+ CloseHandleInProcess(remote_handle_, owning_process_);
+ }
+
+ remote_handle_ = INVALID_HANDLE_VALUE;
+ std::swap(remote_handle_, other.remote_handle_);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ mach_port_name_ = MACH_PORT_NULL;
+ std::swap(mach_port_name_, other.mach_port_name_);
+#endif
+ handle_ = std::move(other.handle_);
+ owning_process_ = std::move(other.owning_process_);
+ return *this;
+}
+
+PlatformHandle PlatformHandleInTransit::TakeHandle() {
+ DCHECK(!owning_process_.is_valid());
+ return std::move(handle_);
+}
+
+void PlatformHandleInTransit::CompleteTransit() {
+#if defined(OS_WIN)
+ remote_handle_ = INVALID_HANDLE_VALUE;
+#endif
+ handle_.release();
+ owning_process_ = ScopedProcessHandle();
+}
+
+bool PlatformHandleInTransit::TransferToProcess(
+ ScopedProcessHandle target_process) {
+ DCHECK(target_process.is_valid());
+ DCHECK(!owning_process_.is_valid());
+ DCHECK(handle_.is_valid());
+#if defined(OS_WIN)
+ remote_handle_ =
+ TransferHandle(handle_.ReleaseHandle(), base::GetCurrentProcessHandle(),
+ target_process.get());
+ if (remote_handle_ == INVALID_HANDLE_VALUE)
+ return false;
+#endif
+ owning_process_ = std::move(target_process);
+ return true;
+}
+
+#if defined(OS_WIN)
+// static
+PlatformHandle PlatformHandleInTransit::TakeIncomingRemoteHandle(
+ HANDLE handle,
+ base::ProcessHandle owning_process) {
+ return PlatformHandle(base::win::ScopedHandle(
+ TransferHandle(handle, owning_process, base::GetCurrentProcessHandle())));
+}
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// static
+PlatformHandleInTransit PlatformHandleInTransit::CreateForMachPortName(
+ mach_port_t name) {
+ if (name == MACH_PORT_NULL) {
+ return PlatformHandleInTransit(
+ PlatformHandle(base::mac::ScopedMachSendRight()));
+ }
+
+ PlatformHandleInTransit handle;
+ handle.mach_port_name_ = name;
+ return handle;
+}
+#endif
+
+} // namespace core
+} // namespace mojo