Avi Drissman | d387f092 | 2022-09-14 20:51:31 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 5 | #ifndef MOJO_CORE_NODE_CHANNEL_H_ |
| 6 | #define MOJO_CORE_NODE_CHANNEL_H_ |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 7 | |
amistry | ba362cd | 2016-03-17 00:53:46 | [diff] [blame] | 8 | #include <utility> |
Wez | 6d83a0b | 2017-11-28 01:17:15 | [diff] [blame] | 9 | #include <vector> |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 10 | |
Brett Wilson | b02c0a2 | 2017-09-25 22:34:42 | [diff] [blame] | 11 | #include "base/containers/queue.h" |
Avi Drissman | d70f89a | 2023-01-11 23:52:55 | [diff] [blame] | 12 | #include "base/functional/callback.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 13 | #include "base/memory/raw_ptr.h" |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 14 | #include "base/memory/ref_counted_delete_on_sequence.h" |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 15 | #include "base/process/process.h" |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 16 | #include "base/process/process_handle.h" |
| 17 | #include "base/synchronization/lock.h" |
Patrick Monette | 643cdf6 | 2021-10-15 19:13:42 | [diff] [blame] | 18 | #include "base/task/single_thread_task_runner.h" |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 19 | #include "build/build_config.h" |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 20 | #include "mojo/core/channel.h" |
| 21 | #include "mojo/core/connection_params.h" |
| 22 | #include "mojo/core/embedder/process_error_callback.h" |
| 23 | #include "mojo/core/ports/name.h" |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 24 | #include "mojo/core/system_impl_export.h" |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 25 | |
| 26 | namespace mojo { |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 27 | namespace core { |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 28 | |
Andrea Orru | 96e9434 | 2024-03-16 01:45:33 | [diff] [blame] | 29 | inline constexpr uint64_t kNodeCapabilityNone = 0; |
| 30 | inline constexpr uint64_t kNodeCapabilitySupportsUpgrade = 1; |
| 31 | |
| 32 | inline constexpr uint32_t kNodeChannelHeaderSize = 8; |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 33 | |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 34 | // Wraps a Channel to send and receive Node control messages. |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 35 | class MOJO_SYSTEM_IMPL_EXPORT NodeChannel |
| 36 | : public base::RefCountedDeleteOnSequence<NodeChannel>, |
| 37 | public Channel::Delegate { |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 38 | public: |
| 39 | class Delegate { |
| 40 | public: |
Anand K Mistry | 48d93df | 2020-06-18 00:04:22 | [diff] [blame] | 41 | virtual ~Delegate() = default; |
Ken Rockot | 02989854 | 2018-02-21 15:13:43 | [diff] [blame] | 42 | virtual void OnAcceptInvitee(const ports::NodeName& from_node, |
| 43 | const ports::NodeName& inviter_name, |
| 44 | const ports::NodeName& token) = 0; |
| 45 | virtual void OnAcceptInvitation(const ports::NodeName& from_node, |
| 46 | const ports::NodeName& token, |
| 47 | const ports::NodeName& invitee_name) = 0; |
rockot | 905ba7f | 2016-02-08 21:16:25 | [diff] [blame] | 48 | virtual void OnAddBrokerClient(const ports::NodeName& from_node, |
| 49 | const ports::NodeName& client_name, |
amistry | e1fcd6a | 2016-02-27 01:49:40 | [diff] [blame] | 50 | base::ProcessHandle process_handle) = 0; |
Ken Rockot | 29b0a32 | 2018-06-29 17:38:07 | [diff] [blame] | 51 | virtual void OnBrokerClientAdded(const ports::NodeName& from_node, |
| 52 | const ports::NodeName& client_name, |
| 53 | PlatformHandle broker_channel) = 0; |
| 54 | virtual void OnAcceptBrokerClient(const ports::NodeName& from_node, |
| 55 | const ports::NodeName& broker_name, |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 56 | PlatformHandle broker_channel, |
| 57 | const uint64_t broker_capabilities) = 0; |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 58 | virtual void OnEventMessage(const ports::NodeName& from_node, |
rockot | 73af395 | 2016-05-17 05:19:33 | [diff] [blame] | 59 | Channel::MessagePtr message) = 0; |
rockot | 7f38d5b | 2016-02-09 20:16:47 | [diff] [blame] | 60 | virtual void OnRequestPortMerge(const ports::NodeName& from_node, |
| 61 | const ports::PortName& connector_port_name, |
| 62 | const std::string& token) = 0; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 63 | virtual void OnRequestIntroduction(const ports::NodeName& from_node, |
| 64 | const ports::NodeName& name) = 0; |
| 65 | virtual void OnIntroduce(const ports::NodeName& from_node, |
| 66 | const ports::NodeName& name, |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 67 | PlatformHandle channel_handle, |
| 68 | const uint64_t remote_capabilities) = 0; |
rockot | 3a91575 | 2016-06-23 20:14:32 | [diff] [blame] | 69 | virtual void OnBroadcast(const ports::NodeName& from_node, |
| 70 | Channel::MessagePtr message) = 0; |
Xiaohan Wang | aa41c68 | 2022-01-14 18:50:49 | [diff] [blame] | 71 | #if BUILDFLAG(IS_WIN) |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 72 | virtual void OnRelayEventMessage(const ports::NodeName& from_node, |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 73 | base::ProcessHandle from_process, |
| 74 | const ports::NodeName& destination, |
| 75 | Channel::MessagePtr message) = 0; |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 76 | virtual void OnEventMessageFromRelay(const ports::NodeName& from_node, |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 77 | const ports::NodeName& source_node, |
| 78 | Channel::MessagePtr message) = 0; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 79 | #endif |
sammc | b0a39f8c | 2016-08-10 06:29:54 | [diff] [blame] | 80 | virtual void OnAcceptPeer(const ports::NodeName& from_node, |
| 81 | const ports::NodeName& token, |
| 82 | const ports::NodeName& peer_name, |
| 83 | const ports::PortName& port_name) = 0; |
amistry | 121c880 | 2016-07-13 05:39:27 | [diff] [blame] | 84 | virtual void OnChannelError(const ports::NodeName& node, |
| 85 | NodeChannel* channel) = 0; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 86 | }; |
| 87 | |
| 88 | static scoped_refptr<NodeChannel> Create( |
| 89 | Delegate* delegate, |
jcivelli | aba5a61 | 2017-03-10 00:28:37 | [diff] [blame] | 90 | ConnectionParams connection_params, |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 91 | Channel::HandlePolicy channel_handle_policy, |
Gabriel Charette | e926fc1 | 2019-12-16 19:00:02 | [diff] [blame] | 92 | scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 93 | const ProcessErrorCallback& process_error_callback); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 94 | |
Peter Boström | feef05a | 2021-10-05 21:35:08 | [diff] [blame] | 95 | NodeChannel(const NodeChannel&) = delete; |
| 96 | NodeChannel& operator=(const NodeChannel&) = delete; |
| 97 | |
Ken Rockot | 559b70d | 2017-07-17 22:35:24 | [diff] [blame] | 98 | static Channel::MessagePtr CreateEventMessage(size_t capacity, |
| 99 | size_t payload_size, |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 100 | void** payload, |
| 101 | size_t num_handles); |
| 102 | |
Ken Rockot | 6740adb28 | 2021-04-07 22:18:36 | [diff] [blame] | 103 | // Retrieves address and size of an Event message's underlying message data. |
| 104 | // Returns `false` if the message is not a valid Event message. |
| 105 | static bool GetEventMessageData(Channel::Message& message, |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 106 | void** data, |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 107 | size_t* num_data_bytes); |
| 108 | |
| 109 | // Start receiving messages. |
| 110 | void Start(); |
| 111 | |
| 112 | // Permanently stop the channel from sending or receiving messages. |
| 113 | void ShutDown(); |
| 114 | |
amistry | e64e296 | 2016-06-15 17:57:27 | [diff] [blame] | 115 | // Leaks the pipe handle instead of closing it on shutdown. |
| 116 | void LeakHandleOnShutdown(); |
| 117 | |
Lukasz Anforowicz | 07cdf115 | 2020-03-24 20:52:50 | [diff] [blame] | 118 | // Invokes the bad message callback for this channel. To avoid losing error |
| 119 | // reports the caller should ensure that the channel |HasBadMessageHandler| |
| 120 | // before calling |NotifyBadMessage|. |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 121 | void NotifyBadMessage(const std::string& error); |
| 122 | |
Lukasz Anforowicz | 07cdf115 | 2020-03-24 20:52:50 | [diff] [blame] | 123 | // Returns whether the channel has a bad message handler. |
| 124 | bool HasBadMessageHandler() { return !process_error_callback_.is_null(); } |
| 125 | |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 126 | void SetRemoteProcessHandle(base::Process process_handle); |
rockot | 905ba7f | 2016-02-08 21:16:25 | [diff] [blame] | 127 | bool HasRemoteProcessHandle(); |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 128 | base::Process CloneRemoteProcessHandle(); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 129 | |
| 130 | // Used for context in Delegate calls (via |from_node| arguments.) |
| 131 | void SetRemoteNodeName(const ports::NodeName& name); |
| 132 | |
Ken Rockot | 02989854 | 2018-02-21 15:13:43 | [diff] [blame] | 133 | void AcceptInvitee(const ports::NodeName& inviter_name, |
| 134 | const ports::NodeName& token); |
| 135 | void AcceptInvitation(const ports::NodeName& token, |
| 136 | const ports::NodeName& invitee_name); |
sammc | b0a39f8c | 2016-08-10 06:29:54 | [diff] [blame] | 137 | void AcceptPeer(const ports::NodeName& sender_name, |
| 138 | const ports::NodeName& token, |
| 139 | const ports::PortName& port_name); |
rockot | 905ba7f | 2016-02-08 21:16:25 | [diff] [blame] | 140 | void AddBrokerClient(const ports::NodeName& client_name, |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 141 | base::Process process_handle); |
rockot | 905ba7f | 2016-02-08 21:16:25 | [diff] [blame] | 142 | void BrokerClientAdded(const ports::NodeName& client_name, |
Ken Rockot | 29b0a32 | 2018-06-29 17:38:07 | [diff] [blame] | 143 | PlatformHandle broker_channel); |
rockot | 905ba7f | 2016-02-08 21:16:25 | [diff] [blame] | 144 | void AcceptBrokerClient(const ports::NodeName& broker_name, |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 145 | PlatformHandle broker_channel, |
| 146 | const uint64_t broker_capabilities); |
rockot | 7f38d5b | 2016-02-09 20:16:47 | [diff] [blame] | 147 | void RequestPortMerge(const ports::PortName& connector_port_name, |
rockot | 90fc3e5 | 2016-02-10 02:36:07 | [diff] [blame] | 148 | const std::string& token); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 149 | void RequestIntroduction(const ports::NodeName& name); |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 150 | void Introduce(const ports::NodeName& name, |
| 151 | PlatformHandle channel_handle, |
| 152 | uint64_t capabilities); |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 153 | void SendChannelMessage(Channel::MessagePtr message); |
rockot | 3a91575 | 2016-06-23 20:14:32 | [diff] [blame] | 154 | void Broadcast(Channel::MessagePtr message); |
Ken Rockot | ed81c77 | 2019-09-20 06:41:17 | [diff] [blame] | 155 | void BindBrokerHost(PlatformHandle broker_host_handle); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 156 | |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 157 | uint64_t RemoteCapabilities() const; |
| 158 | bool HasRemoteCapability(const uint64_t capability) const; |
| 159 | void SetRemoteCapabilities(const uint64_t capability); |
| 160 | |
| 161 | uint64_t LocalCapabilities() const; |
| 162 | bool HasLocalCapability(const uint64_t capability) const; |
| 163 | void SetLocalCapabilities(const uint64_t capability); |
| 164 | |
Xiaohan Wang | aa41c68 | 2022-01-14 18:50:49 | [diff] [blame] | 165 | #if BUILDFLAG(IS_WIN) |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 166 | // Relay the message to the specified node via this channel. This is used to |
| 167 | // pass windows handles between two processes that do not have permission to |
| 168 | // duplicate handles into the other's address space. The relay process is |
| 169 | // assumed to have that permission. |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 170 | void RelayEventMessage(const ports::NodeName& destination, |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 171 | Channel::MessagePtr message); |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 172 | |
| 173 | // Sends a message to its destination from a relay. This is interpreted by the |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 174 | // receiver similarly to EventMessage, but the original source node is |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 175 | // provided as additional message metadata from the (trusted) relay node. |
Ken Rockot | 5d98372 | 2017-05-31 04:46:57 | [diff] [blame] | 176 | void EventMessageFromRelay(const ports::NodeName& source, |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 177 | Channel::MessagePtr message); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 178 | #endif |
| 179 | |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 180 | void OfferChannelUpgrade(); |
| 181 | |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 182 | private: |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 183 | friend class base::RefCountedDeleteOnSequence<NodeChannel>; |
| 184 | friend class base::DeleteHelper<NodeChannel>; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 185 | |
Brett Wilson | b02c0a2 | 2017-09-25 22:34:42 | [diff] [blame] | 186 | using PendingMessageQueue = base::queue<Channel::MessagePtr>; |
amistry | ba362cd | 2016-03-17 00:53:46 | [diff] [blame] | 187 | using PendingRelayMessageQueue = |
Brett Wilson | b02c0a2 | 2017-09-25 22:34:42 | [diff] [blame] | 188 | base::queue<std::pair<ports::NodeName, Channel::MessagePtr>>; |
amistry | ba362cd | 2016-03-17 00:53:46 | [diff] [blame] | 189 | |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 190 | NodeChannel(Delegate* delegate, |
jcivelli | aba5a61 | 2017-03-10 00:28:37 | [diff] [blame] | 191 | ConnectionParams connection_params, |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 192 | Channel::HandlePolicy channel_handle_policy, |
Gabriel Charette | e926fc1 | 2019-12-16 19:00:02 | [diff] [blame] | 193 | scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 194 | const ProcessErrorCallback& process_error_callback); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 195 | ~NodeChannel() override; |
| 196 | |
Ken Rockot | ed81c77 | 2019-09-20 06:41:17 | [diff] [blame] | 197 | // Creates a BrokerHost to satisfy a |BindBrokerHost()| request from the other |
| 198 | // end of the channel. |
| 199 | void CreateAndBindLocalBrokerHost(PlatformHandle broker_host_handle); |
| 200 | |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 201 | // Channel::Delegate: |
Ken Rockot | 043152da6 | 2018-06-29 03:22:16 | [diff] [blame] | 202 | void OnChannelMessage(const void* payload, |
| 203 | size_t payload_size, |
Scott Violet | dd480bc | 2024-10-16 21:15:14 | [diff] [blame] | 204 | std::vector<PlatformHandle> handles, |
| 205 | scoped_refptr<ipcz_driver::Envelope> envelope) override; |
Ken Rockot | 7f49ca4 | 2017-07-13 00:17:26 | [diff] [blame] | 206 | void OnChannelError(Channel::Error error) override; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 207 | |
| 208 | void WriteChannelMessage(Channel::MessagePtr message); |
| 209 | |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 210 | // This method is responsible for setting up the default set of capabilities |
| 211 | // for this channel. |
| 212 | void InitializeLocalCapabilities(); |
| 213 | |
Pâris | 146ae0c1 | 2023-06-08 17:43:43 | [diff] [blame] | 214 | // This dangling raw_ptr occurred in: |
| 215 | // mojo_unittests: NodeChannelTest.MessagesCannotBeSmallerThanOldestVersion |
| 216 | // https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/1425190/test-results?q=ExactID%3Aninja%3A%2F%2Fmojo%3Amojo_unittests%2FNodeChannelTest.MessagesCannotBeSmallerThanOldestVersion+VHash%3A589215eb23c7875a |
| 217 | const raw_ptr<Delegate, FlakyDanglingUntriaged> delegate_; |
rockot | b46bf91 | 2016-06-11 23:18:16 | [diff] [blame] | 218 | const ProcessErrorCallback process_error_callback_; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 219 | |
| 220 | base::Lock channel_lock_; |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 221 | scoped_refptr<Channel> channel_ GUARDED_BY(channel_lock_); |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 222 | |
Ken Rockot | 9f9ebab3 | 2020-08-17 20:09:19 | [diff] [blame] | 223 | // Must only be accessed from the owning task runner's thread. |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 224 | ports::NodeName remote_node_name_; |
| 225 | |
Brian Geffon | 12b581a | 2021-02-03 23:48:03 | [diff] [blame] | 226 | uint64_t remote_capabilities_ = kNodeCapabilityNone; |
| 227 | uint64_t local_capabilities_ = kNodeCapabilityNone; |
| 228 | |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 229 | base::Lock remote_process_handle_lock_; |
Robert Sesek | 0e7f165a | 2020-11-20 21:31:45 | [diff] [blame] | 230 | base::Process remote_process_handle_; |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 231 | }; |
| 232 | |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 233 | } // namespace core |
rockot | ce69a04 | 2016-01-26 19:23:21 | [diff] [blame] | 234 | } // namespace mojo |
| 235 | |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 236 | #endif // MOJO_CORE_NODE_CHANNEL_H_ |