Home | History | Annotate | Download | only in ipc
      1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ipc/ipc_message_attachment.h"
      6 
      7 #include "base/files/scoped_file.h"
      8 #include "base/logging.h"
      9 #include "ipc/ipc_mojo_handle_attachment.h"
     10 #include "mojo/public/cpp/system/platform_handle.h"
     11 
     12 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
     13 #include "base/posix/eintr_wrapper.h"
     14 #include "ipc/ipc_platform_file_attachment_posix.h"
     15 #endif
     16 
     17 #if defined(OS_MACOSX) && !defined(OS_IOS)
     18 #include "ipc/mach_port_attachment_mac.h"
     19 #endif
     20 
     21 #if defined(OS_WIN)
     22 #include "ipc/handle_attachment_win.h"
     23 #endif
     24 
     25 #if defined(OS_FUCHSIA)
     26 #include "ipc/handle_attachment_fuchsia.h"
     27 #endif
     28 
     29 namespace IPC {
     30 
     31 namespace {
     32 
     33 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
     34 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
     35   return attachment->Owns()
     36              ? base::ScopedFD(attachment->TakePlatformFile())
     37              : base::ScopedFD(HANDLE_EINTR(dup(attachment->file())));
     38 }
     39 #endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
     40 
     41 }  // namespace
     42 
     43 MessageAttachment::MessageAttachment() = default;
     44 
     45 MessageAttachment::~MessageAttachment() = default;
     46 
     47 mojo::ScopedHandle MessageAttachment::TakeMojoHandle() {
     48   switch (GetType()) {
     49     case Type::MOJO_HANDLE:
     50       return static_cast<internal::MojoHandleAttachment*>(this)->TakeHandle();
     51 
     52 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
     53     case Type::PLATFORM_FILE: {
     54       // We dup() the handles in IPC::Message to transmit.
     55       // IPC::MessageAttachmentSet has intricate lifetime semantics for FDs, so
     56       // just to dup()-and-own them is the safest option.
     57       base::ScopedFD file =
     58           TakeOrDupFile(static_cast<internal::PlatformFileAttachment*>(this));
     59       if (!file.is_valid()) {
     60         DPLOG(WARNING) << "Failed to dup FD to transmit.";
     61         return mojo::ScopedHandle();
     62       }
     63       return mojo::WrapPlatformFile(file.release());
     64     }
     65 #endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
     66 
     67 #if defined(OS_MACOSX) && !defined(OS_IOS)
     68     case Type::MACH_PORT: {
     69       auto* attachment = static_cast<internal::MachPortAttachmentMac*>(this);
     70       MojoPlatformHandle platform_handle = {
     71           sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT,
     72           static_cast<uint64_t>(attachment->get_mach_port())};
     73       MojoHandle wrapped_handle;
     74       if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
     75           MOJO_RESULT_OK) {
     76         return mojo::ScopedHandle();
     77       }
     78       attachment->reset_mach_port_ownership();
     79       return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
     80     }
     81 #elif defined(OS_FUCHSIA)
     82     case Type::FUCHSIA_HANDLE: {
     83       auto* attachment = static_cast<internal::HandleAttachmentFuchsia*>(this);
     84       MojoPlatformHandle platform_handle = {
     85           sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE,
     86           static_cast<uint64_t>(attachment->Take())};
     87       MojoHandle wrapped_handle;
     88       if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
     89           MOJO_RESULT_OK) {
     90         return mojo::ScopedHandle();
     91       }
     92       return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
     93     }
     94 #elif defined(OS_WIN)
     95     case Type::WIN_HANDLE:
     96       return mojo::WrapPlatformFile(
     97           static_cast<internal::HandleAttachmentWin*>(this)->Take());
     98 #endif
     99     default:
    100       break;
    101   }
    102   NOTREACHED();
    103   return mojo::ScopedHandle();
    104 }
    105 
    106 // static
    107 scoped_refptr<MessageAttachment> MessageAttachment::CreateFromMojoHandle(
    108     mojo::ScopedHandle handle,
    109     Type type) {
    110   if (type == Type::MOJO_HANDLE)
    111     return new internal::MojoHandleAttachment(std::move(handle));
    112 
    113   MojoPlatformHandle platform_handle = {sizeof(platform_handle), 0, 0};
    114   MojoResult unwrap_result = MojoUnwrapPlatformHandle(
    115       handle.release().value(), nullptr, &platform_handle);
    116   if (unwrap_result != MOJO_RESULT_OK)
    117     return nullptr;
    118 
    119 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    120   if (type == Type::PLATFORM_FILE) {
    121     base::PlatformFile file = base::kInvalidPlatformFile;
    122     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
    123       file = static_cast<base::PlatformFile>(platform_handle.value);
    124     return new internal::PlatformFileAttachment(file);
    125   }
    126 #endif  // defined(OS_POSIX) || defined(OS_FUCHSIA)
    127 
    128 #if defined(OS_MACOSX) && !defined(OS_IOS)
    129   if (type == Type::MACH_PORT) {
    130     mach_port_t mach_port = MACH_PORT_NULL;
    131     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
    132       mach_port = static_cast<mach_port_t>(platform_handle.value);
    133     return new internal::MachPortAttachmentMac(
    134         mach_port, internal::MachPortAttachmentMac::FROM_WIRE);
    135   }
    136 #elif defined(OS_FUCHSIA)
    137   if (type == Type::FUCHSIA_HANDLE) {
    138     zx::handle handle;
    139     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
    140       handle.reset(static_cast<zx_handle_t>(platform_handle.value));
    141     return new internal::HandleAttachmentFuchsia(std::move(handle));
    142   }
    143 #elif defined(OS_WIN)
    144   if (type == Type::WIN_HANDLE) {
    145     base::PlatformFile handle = base::kInvalidPlatformFile;
    146     if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
    147       handle = reinterpret_cast<base::PlatformFile>(platform_handle.value);
    148     return new internal::HandleAttachmentWin(
    149         handle, internal::HandleAttachmentWin::FROM_WIRE);
    150   }
    151 #endif
    152   NOTREACHED();
    153   return nullptr;
    154 }
    155 
    156 }  // namespace IPC
    157