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 |