| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/system/platform_channel.h" | 5 #include "mojo/system/platform_channel.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/socket.h> | 8 #include <sys/socket.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| 11 | 11 |
| 12 #include "base/command_line.h" |
| 12 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/posix/global_descriptors.h" |
| 16 #include "base/strings/string_number_conversions.h" |
| 14 | 17 |
| 15 namespace mojo { | 18 namespace mojo { |
| 16 namespace system { | 19 namespace system { |
| 17 | 20 |
| 18 namespace { | 21 namespace { |
| 19 | 22 |
| 20 void CloseIfNecessary(PlatformChannelHandle* handle) { | 23 const char kMojoChannelDescriptorSwitch[] = "mojo-channel-descriptor"; |
| 21 if (!handle->is_valid()) | |
| 22 return; | |
| 23 | 24 |
| 24 PCHECK(close(handle->fd) == 0); | 25 bool IsTargetDescriptorUsed( |
| 25 *handle = PlatformChannelHandle(); | 26 const base::FileHandleMappingVector& file_handle_mapping, |
| 27 int target_fd) { |
| 28 for (size_t i = 0; i < file_handle_mapping.size(); i++) { |
| 29 if (file_handle_mapping[i].second == target_fd) |
| 30 return true; |
| 31 } |
| 32 return false; |
| 26 } | 33 } |
| 27 | 34 |
| 28 class PlatformServerChannelPosix : public PlatformServerChannel { | 35 class PlatformServerChannelPosix : public PlatformServerChannel { |
| 29 public: | 36 public: |
| 30 PlatformServerChannelPosix(const std::string& name); | 37 PlatformServerChannelPosix(const std::string& name); |
| 31 virtual ~PlatformServerChannelPosix(); | 38 virtual ~PlatformServerChannelPosix(); |
| 32 | 39 |
| 33 // |PlatformServerChannel| implementation: | 40 // |PlatformServerChannel| implementation: |
| 34 virtual scoped_ptr<PlatformClientChannel> CreateClientChannel() OVERRIDE; | 41 virtual scoped_ptr<PlatformClientChannel> CreateClientChannel() OVERRIDE; |
| 35 virtual void GetDataNeededToPassClientChannelToChildProcess( | 42 virtual void GetDataNeededToPassClientChannelToChildProcess( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 52 PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0); | 59 PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0); |
| 53 PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0); | 60 PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0); |
| 54 | 61 |
| 55 mutable_handle()->fd = fds[0]; | 62 mutable_handle()->fd = fds[0]; |
| 56 DCHECK(is_valid()); | 63 DCHECK(is_valid()); |
| 57 client_handle_.fd = fds[1]; | 64 client_handle_.fd = fds[1]; |
| 58 DCHECK(client_handle_.is_valid()); | 65 DCHECK(client_handle_.is_valid()); |
| 59 } | 66 } |
| 60 | 67 |
| 61 PlatformServerChannelPosix::~PlatformServerChannelPosix() { | 68 PlatformServerChannelPosix::~PlatformServerChannelPosix() { |
| 62 if (is_valid()) | 69 client_handle_.CloseIfNecessary(); |
| 63 CloseIfNecessary(mutable_handle()); | |
| 64 if (client_handle_.is_valid()) | |
| 65 CloseIfNecessary(&client_handle_); | |
| 66 } | 70 } |
| 67 | 71 |
| 68 scoped_ptr<PlatformClientChannel> | 72 scoped_ptr<PlatformClientChannel> |
| 69 PlatformServerChannelPosix::CreateClientChannel() { | 73 PlatformServerChannelPosix::CreateClientChannel() { |
| 70 if (!client_handle_.is_valid()) { | 74 if (!client_handle_.is_valid()) { |
| 71 NOTREACHED(); | 75 NOTREACHED(); |
| 72 return scoped_ptr<PlatformClientChannel>(); | 76 return scoped_ptr<PlatformClientChannel>(); |
| 73 } | 77 } |
| 74 | 78 |
| 75 scoped_ptr<PlatformClientChannel> rv = | 79 scoped_ptr<PlatformClientChannel> rv = |
| 76 PlatformClientChannel::CreateFromHandle(client_handle_); | 80 PlatformClientChannel::CreateFromHandle(client_handle_); |
| 77 DCHECK(rv->is_valid()); | 81 DCHECK(rv->is_valid()); |
| 78 client_handle_ = PlatformChannelHandle(); | 82 client_handle_ = PlatformChannelHandle(); |
| 79 return rv.Pass(); | 83 return rv.Pass(); |
| 80 } | 84 } |
| 81 | 85 |
| 82 void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess( | 86 void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess( |
| 83 CommandLine* command_line, | 87 CommandLine* command_line, |
| 84 base::FileHandleMappingVector* file_handle_mapping) const { | 88 base::FileHandleMappingVector* file_handle_mapping) const { |
| 85 // TODO(vtl) | 89 DCHECK(command_line); |
| 86 NOTIMPLEMENTED(); | 90 DCHECK(file_handle_mapping); |
| 91 // This is an arbitrary sanity check. (Note that this guarantees that the loop |
| 92 // below will terminate sanely.) |
| 93 CHECK_LT(file_handle_mapping->size(), 1000u); |
| 94 |
| 95 DCHECK(client_handle_.is_valid()); |
| 96 |
| 97 // Find a suitable FD to map our client handle to in the child process. |
| 98 // This has quadratic time complexity in the size of |*file_handle_mapping|, |
| 99 // but |*file_handle_mapping| should be very small (usually/often empty). |
| 100 int target_fd = base::GlobalDescriptors::kBaseDescriptor; |
| 101 while (IsTargetDescriptorUsed(*file_handle_mapping, target_fd)) |
| 102 target_fd++; |
| 103 |
| 104 file_handle_mapping->push_back(std::pair<int, int>(client_handle_.fd, |
| 105 target_fd)); |
| 106 // Log a warning if the command line already has the switch, but "clobber" it |
| 107 // anyway, since it's reasonably likely that all the switches were just copied |
| 108 // from the parent. |
| 109 LOG_IF(WARNING, command_line->HasSwitch(kMojoChannelDescriptorSwitch)) |
| 110 << "Child command line already has switch --" |
| 111 << kMojoChannelDescriptorSwitch << "=" |
| 112 << command_line->GetSwitchValueASCII(kMojoChannelDescriptorSwitch); |
| 113 // (Any existing switch won't actually be removed from the command line, but |
| 114 // the last one appended takes precedence.) |
| 115 command_line->AppendSwitchASCII(kMojoChannelDescriptorSwitch, |
| 116 base::IntToString(target_fd)); |
| 87 } | 117 } |
| 88 | 118 |
| 89 void PlatformServerChannelPosix::ChildProcessLaunched() { | 119 void PlatformServerChannelPosix::ChildProcessLaunched() { |
| 90 // TODO(vtl) | 120 DCHECK(client_handle_.is_valid()); |
| 91 NOTIMPLEMENTED(); | 121 client_handle_.CloseIfNecessary(); |
| 92 } | 122 } |
| 93 | 123 |
| 94 } // namespace | 124 } // namespace |
| 95 | 125 |
| 96 // ----------------------------------------------------------------------------- | 126 // ----------------------------------------------------------------------------- |
| 97 | 127 |
| 98 // Static factory method declared in platform_channel.h. | 128 // Static factory method declared in platform_channel.h. |
| 99 // static | 129 // static |
| 100 scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create( | 130 scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create( |
| 101 const std::string& name) { | 131 const std::string& name) { |
| 102 return scoped_ptr<PlatformServerChannel>( | 132 return scoped_ptr<PlatformServerChannel>( |
| 103 new PlatformServerChannelPosix(name)); | 133 new PlatformServerChannelPosix(name)); |
| 104 } | 134 } |
| 105 | 135 |
| 106 // ----------------------------------------------------------------------------- | 136 // ----------------------------------------------------------------------------- |
| 107 | 137 |
| 108 // Static factory method declared in platform_channel.h. | 138 // Static factory method declared in platform_channel.h. |
| 109 // static | 139 // static |
| 110 scoped_ptr<PlatformClientChannel> | 140 scoped_ptr<PlatformClientChannel> |
| 111 PlatformClientChannel::CreateFromParentProcess( | 141 PlatformClientChannel::CreateFromParentProcess( |
| 112 const CommandLine& command_line) { | 142 const CommandLine& command_line) { |
| 113 // TODO(vtl) | 143 std::string client_fd_string = |
| 114 NOTIMPLEMENTED(); | 144 command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch); |
| 115 return scoped_ptr<PlatformClientChannel>(); | 145 int client_fd = -1; |
| 146 if (client_fd_string.empty() || |
| 147 !base::StringToInt(client_fd_string, &client_fd) || |
| 148 client_fd < base::GlobalDescriptors::kBaseDescriptor) { |
| 149 LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch; |
| 150 return scoped_ptr<PlatformClientChannel>(); |
| 151 } |
| 152 |
| 153 return CreateFromHandle(PlatformChannelHandle(client_fd)); |
| 116 } | 154 } |
| 117 | 155 |
| 118 } // namespace system | 156 } // namespace system |
| 119 } // namespace mojo | 157 } // namespace mojo |
| OLD | NEW |