| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_pair.h" | 5 #include "mojo/system/platform_channel_pair.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/command_line.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/posix/global_descriptors.h" | 14 #include "base/posix/global_descriptors.h" |
| 15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "mojo/system/platform_channel.h" | 16 #include "mojo/system/platform_handle.h" |
| 17 | 17 |
| 18 namespace mojo { | 18 namespace mojo { |
| 19 namespace system { | 19 namespace system { |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 | 22 |
| 23 const char kMojoChannelDescriptorSwitch[] = "mojo-channel-descriptor"; | 23 const char kMojoChannelDescriptorSwitch[] = "mojo-channel-descriptor"; |
| 24 | 24 |
| 25 bool IsTargetDescriptorUsed( | 25 bool IsTargetDescriptorUsed( |
| 26 const base::FileHandleMappingVector& file_handle_mapping, | 26 const base::FileHandleMappingVector& file_handle_mapping, |
| 27 int target_fd) { | 27 int target_fd) { |
| 28 for (size_t i = 0; i < file_handle_mapping.size(); i++) { | 28 for (size_t i = 0; i < file_handle_mapping.size(); i++) { |
| 29 if (file_handle_mapping[i].second == target_fd) | 29 if (file_handle_mapping[i].second == target_fd) |
| 30 return true; | 30 return true; |
| 31 } | 31 } |
| 32 return false; | 32 return false; |
| 33 } | 33 } |
| 34 | 34 |
| 35 } // namespace | 35 } // namespace |
| 36 | 36 |
| 37 PlatformChannelPair::PlatformChannelPair() { | 37 PlatformChannelPair::PlatformChannelPair() { |
| 38 // Create the Unix domain socket and set the ends to nonblocking. | 38 // Create the Unix domain socket and set the ends to nonblocking. |
| 39 int fds[2]; | 39 int fds[2]; |
| 40 // TODO(vtl): Maybe fail gracefully if |socketpair()| fails. | 40 // TODO(vtl): Maybe fail gracefully if |socketpair()| fails. |
| 41 PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0); | 41 PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0); |
| 42 PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0); | 42 PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0); |
| 43 PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0); | 43 PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0); |
| 44 | 44 |
| 45 server_handle_.fd = fds[0]; | 45 server_handle_.reset(PlatformHandle(fds[0])); |
| 46 DCHECK(server_handle_.is_valid()); | 46 DCHECK(server_handle_.is_valid()); |
| 47 client_handle_.fd = fds[1]; | 47 client_handle_.reset(PlatformHandle(fds[1])); |
| 48 DCHECK(client_handle_.is_valid()); | 48 DCHECK(client_handle_.is_valid()); |
| 49 } | 49 } |
| 50 | 50 |
| 51 // static | 51 // static |
| 52 scoped_ptr<PlatformChannel> | 52 ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess( |
| 53 PlatformChannelPair::CreateClientChannelFromParentProcess( | |
| 54 const CommandLine& command_line) { | 53 const CommandLine& command_line) { |
| 55 std::string client_fd_string = | 54 std::string client_fd_string = |
| 56 command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch); | 55 command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch); |
| 57 int client_fd = -1; | 56 int client_fd = -1; |
| 58 if (client_fd_string.empty() || | 57 if (client_fd_string.empty() || |
| 59 !base::StringToInt(client_fd_string, &client_fd) || | 58 !base::StringToInt(client_fd_string, &client_fd) || |
| 60 client_fd < base::GlobalDescriptors::kBaseDescriptor) { | 59 client_fd < base::GlobalDescriptors::kBaseDescriptor) { |
| 61 LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch; | 60 LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch; |
| 62 return scoped_ptr<PlatformChannel>(); | 61 return ScopedPlatformHandle(); |
| 63 } | 62 } |
| 64 | 63 |
| 65 return PlatformChannel::CreateFromHandle(PlatformChannelHandle(client_fd)); | 64 return ScopedPlatformHandle(PlatformHandle(client_fd)); |
| 66 } | 65 } |
| 67 | 66 |
| 68 void PlatformChannelPair::PrepareToPassClientChannelToChildProcess( | 67 void PlatformChannelPair::PrepareToPassClientHandleToChildProcess( |
| 69 CommandLine* command_line, | 68 CommandLine* command_line, |
| 70 base::FileHandleMappingVector* file_handle_mapping) const { | 69 base::FileHandleMappingVector* file_handle_mapping) const { |
| 71 DCHECK(command_line); | 70 DCHECK(command_line); |
| 72 DCHECK(file_handle_mapping); | 71 DCHECK(file_handle_mapping); |
| 73 // This is an arbitrary sanity check. (Note that this guarantees that the loop | 72 // This is an arbitrary sanity check. (Note that this guarantees that the loop |
| 74 // below will terminate sanely.) | 73 // below will terminate sanely.) |
| 75 CHECK_LT(file_handle_mapping->size(), 1000u); | 74 CHECK_LT(file_handle_mapping->size(), 1000u); |
| 76 | 75 |
| 77 DCHECK(client_handle_.is_valid()); | 76 DCHECK(client_handle_.is_valid()); |
| 78 | 77 |
| 79 // Find a suitable FD to map our client handle to in the child process. | 78 // Find a suitable FD to map our client handle to in the child process. |
| 80 // This has quadratic time complexity in the size of |*file_handle_mapping|, | 79 // This has quadratic time complexity in the size of |*file_handle_mapping|, |
| 81 // but |*file_handle_mapping| should be very small (usually/often empty). | 80 // but |*file_handle_mapping| should be very small (usually/often empty). |
| 82 int target_fd = base::GlobalDescriptors::kBaseDescriptor; | 81 int target_fd = base::GlobalDescriptors::kBaseDescriptor; |
| 83 while (IsTargetDescriptorUsed(*file_handle_mapping, target_fd)) | 82 while (IsTargetDescriptorUsed(*file_handle_mapping, target_fd)) |
| 84 target_fd++; | 83 target_fd++; |
| 85 | 84 |
| 86 file_handle_mapping->push_back(std::pair<int, int>(client_handle_.fd, | 85 file_handle_mapping->push_back(std::pair<int, int>(client_handle_.get().fd, |
| 87 target_fd)); | 86 target_fd)); |
| 88 // Log a warning if the command line already has the switch, but "clobber" it | 87 // Log a warning if the command line already has the switch, but "clobber" it |
| 89 // anyway, since it's reasonably likely that all the switches were just copied | 88 // anyway, since it's reasonably likely that all the switches were just copied |
| 90 // from the parent. | 89 // from the parent. |
| 91 LOG_IF(WARNING, command_line->HasSwitch(kMojoChannelDescriptorSwitch)) | 90 LOG_IF(WARNING, command_line->HasSwitch(kMojoChannelDescriptorSwitch)) |
| 92 << "Child command line already has switch --" | 91 << "Child command line already has switch --" |
| 93 << kMojoChannelDescriptorSwitch << "=" | 92 << kMojoChannelDescriptorSwitch << "=" |
| 94 << command_line->GetSwitchValueASCII(kMojoChannelDescriptorSwitch); | 93 << command_line->GetSwitchValueASCII(kMojoChannelDescriptorSwitch); |
| 95 // (Any existing switch won't actually be removed from the command line, but | 94 // (Any existing switch won't actually be removed from the command line, but |
| 96 // the last one appended takes precedence.) | 95 // the last one appended takes precedence.) |
| 97 command_line->AppendSwitchASCII(kMojoChannelDescriptorSwitch, | 96 command_line->AppendSwitchASCII(kMojoChannelDescriptorSwitch, |
| 98 base::IntToString(target_fd)); | 97 base::IntToString(target_fd)); |
| 99 } | 98 } |
| 100 | 99 |
| 101 void PlatformChannelPair::ChildProcessLaunched() { | 100 void PlatformChannelPair::ChildProcessLaunched() { |
| 102 DCHECK(client_handle_.is_valid()); | 101 DCHECK(client_handle_.is_valid()); |
| 103 client_handle_.CloseIfNecessary(); | 102 client_handle_.reset(); |
| 104 } | 103 } |
| 105 | 104 |
| 106 } // namespace system | 105 } // namespace system |
| 107 } // namespace mojo | 106 } // namespace mojo |
| OLD | NEW |