[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 1 | // Copyright (c) 2012 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_channel_nacl.h" |
| 6 | |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 7 | #include <errno.h> |
| 8 | #include <stddef.h> |
tfarina | 10a5c06 | 2015-09-04 18:47:57 | [diff] [blame] | 9 | #include <stdint.h> |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 10 | #include <sys/types.h> |
| 11 | |
| 12 | #include <algorithm> |
| 13 | |
| 14 | #include "base/bind.h" |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 15 | #include "base/logging.h" |
avi | 246998d8 | 2015-12-22 02:39:04 | [diff] [blame] | 16 | #include "base/macros.h" |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 17 | #include "base/single_thread_task_runner.h" |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 18 | #include "base/synchronization/lock.h" |
| 19 | #include "base/task_runner_util.h" |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 20 | #include "base/thread_task_runner_handle.h" |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 21 | #include "base/threading/simple_thread.h" |
[email protected] | 7e3d752 | 2014-03-20 21:00:50 | [diff] [blame] | 22 | #include "ipc/ipc_listener.h" |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 23 | #include "ipc/ipc_logging.h" |
morrita | 4b5c28e2 | 2015-01-14 21:17:06 | [diff] [blame] | 24 | #include "ipc/ipc_message_attachment_set.h" |
[email protected] | 18ff3c3 | 2013-06-05 23:37:11 | [diff] [blame] | 25 | #include "native_client/src/public/imc_syscalls.h" |
| 26 | #include "native_client/src/public/imc_types.h" |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 27 | |
| 28 | namespace IPC { |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 29 | |
| 30 | struct MessageContents { |
| 31 | std::vector<char> data; |
| 32 | std::vector<int> fds; |
| 33 | }; |
| 34 | |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 35 | namespace { |
| 36 | |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 37 | bool ReadDataOnReaderThread(int pipe, MessageContents* contents) { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 38 | DCHECK(pipe >= 0); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 39 | if (pipe < 0) |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 40 | return false; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 41 | |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 42 | contents->data.resize(Channel::kReadBufferSize); |
yusukes | eaa3c5bf | 2015-03-17 00:34:13 | [diff] [blame] | 43 | contents->fds.resize(NACL_ABI_IMC_DESC_MAX); |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 44 | |
[email protected] | 18ff3c3 | 2013-06-05 23:37:11 | [diff] [blame] | 45 | NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() }; |
| 46 | NaClAbiNaClImcMsgHdr msg = { |
| 47 | &iov, 1, &contents->fds[0], contents->fds.size() |
| 48 | }; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 49 | |
| 50 | int bytes_read = imc_recvmsg(pipe, &msg, 0); |
| 51 | |
| 52 | if (bytes_read <= 0) { |
| 53 | // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either |
| 54 | // due to error or for regular shutdown). |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 55 | contents->data.clear(); |
| 56 | contents->fds.clear(); |
| 57 | return false; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 58 | } |
| 59 | DCHECK(bytes_read); |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 60 | // Resize the buffers down to the number of bytes and fds we actually read. |
| 61 | contents->data.resize(bytes_read); |
| 62 | contents->fds.resize(msg.desc_length); |
| 63 | return true; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | } // namespace |
| 67 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 68 | class ChannelNacl::ReaderThreadRunner |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 69 | : public base::DelegateSimpleThread::Delegate { |
| 70 | public: |
| 71 | // |pipe|: A file descriptor from which we will read using imc_recvmsg. |
| 72 | // |data_read_callback|: A callback we invoke (on the main thread) when we |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 73 | // have read data. |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 74 | // |failure_callback|: A callback we invoke when we have a failure reading |
| 75 | // from |pipe|. |
| 76 | // |main_message_loop|: A proxy for the main thread, where we will invoke the |
| 77 | // above callbacks. |
| 78 | ReaderThreadRunner( |
| 79 | int pipe, |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 80 | base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback, |
| 81 | base::Callback<void()> failure_callback, |
| 82 | scoped_refptr<base::SingleThreadTaskRunner> main_task_runner); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 83 | |
| 84 | // DelegateSimpleThread implementation. Reads data from the pipe in a loop |
| 85 | // until either we are told to quit or a read fails. |
nick | d60f717 | 2015-04-23 16:42:48 | [diff] [blame] | 86 | void Run() override; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 87 | |
| 88 | private: |
| 89 | int pipe_; |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 90 | base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 91 | base::Callback<void ()> failure_callback_; |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 92 | scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 93 | |
| 94 | DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner); |
| 95 | }; |
| 96 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 97 | ChannelNacl::ReaderThreadRunner::ReaderThreadRunner( |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 98 | int pipe, |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 99 | base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback, |
| 100 | base::Callback<void()> failure_callback, |
| 101 | scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 102 | : pipe_(pipe), |
| 103 | data_read_callback_(data_read_callback), |
| 104 | failure_callback_(failure_callback), |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 105 | main_task_runner_(main_task_runner) { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 106 | } |
| 107 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 108 | void ChannelNacl::ReaderThreadRunner::Run() { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 109 | while (true) { |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 110 | scoped_ptr<MessageContents> msg_contents(new MessageContents); |
| 111 | bool success = ReadDataOnReaderThread(pipe_, msg_contents.get()); |
| 112 | if (success) { |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 113 | main_task_runner_->PostTask( |
| 114 | FROM_HERE, |
[email protected] | d873f19 | 2013-01-23 02:20:35 | [diff] [blame] | 115 | base::Bind(data_read_callback_, base::Passed(&msg_contents))); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 116 | } else { |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 117 | main_task_runner_->PostTask(FROM_HERE, failure_callback_); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 118 | // Because the read failed, we know we're going to quit. Don't bother |
| 119 | // trying to read again. |
| 120 | return; |
| 121 | } |
| 122 | } |
| 123 | } |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 124 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 125 | ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle, |
| 126 | Mode mode, |
erikchen | 30dc281 | 2015-09-24 03:26:38 | [diff] [blame] | 127 | Listener* listener) |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 128 | : ChannelReader(listener), |
| 129 | mode_(mode), |
| 130 | waiting_connect_(true), |
| 131 | pipe_(-1), |
| 132 | pipe_name_(channel_handle.name), |
erikchen | 5708aae | 2015-09-14 17:45:12 | [diff] [blame] | 133 | weak_ptr_factory_(this) { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 134 | if (!CreatePipe(channel_handle)) { |
| 135 | // The pipe may have been closed already. |
| 136 | const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client"; |
| 137 | LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name |
| 138 | << "\" in " << modestr << " mode"; |
| 139 | } |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 140 | } |
| 141 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 142 | ChannelNacl::~ChannelNacl() { |
erikchen | 53d919d | 2015-09-11 17:33:34 | [diff] [blame] | 143 | CleanUp(); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 144 | Close(); |
| 145 | } |
| 146 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 147 | base::ProcessId ChannelNacl::GetPeerPID() const { |
[email protected] | 7e3d752 | 2014-03-20 21:00:50 | [diff] [blame] | 148 | // This shouldn't actually get used in the untrusted side of the proxy, and we |
| 149 | // don't have the real pid anyway. |
| 150 | return -1; |
| 151 | } |
| 152 | |
[email protected] | 6486088 | 2014-08-04 23:44:17 | [diff] [blame] | 153 | base::ProcessId ChannelNacl::GetSelfPID() const { |
| 154 | return -1; |
| 155 | } |
| 156 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 157 | bool ChannelNacl::Connect() { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 158 | if (pipe_ == -1) { |
[email protected] | 7e3d752 | 2014-03-20 21:00:50 | [diff] [blame] | 159 | DLOG(WARNING) << "Channel creation failed: " << pipe_name_; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 160 | return false; |
| 161 | } |
| 162 | |
[email protected] | cf0e7ee | 2012-07-11 00:49:17 | [diff] [blame] | 163 | // Note that Connect is called on the "Channel" thread (i.e., the same thread |
| 164 | // where Channel::Send will be called, and the same thread that should receive |
| 165 | // messages). The constructor might be invoked on another thread (see |
| 166 | // ChannelProxy for an example of that). Therefore, we must wait until Connect |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 167 | // is called to decide which SingleThreadTaskRunner to pass to |
| 168 | // ReaderThreadRunner. |
| 169 | reader_thread_runner_.reset(new ReaderThreadRunner( |
| 170 | pipe_, |
| 171 | base::Bind(&ChannelNacl::DidRecvMsg, weak_ptr_factory_.GetWeakPtr()), |
| 172 | base::Bind(&ChannelNacl::ReadDidFail, weak_ptr_factory_.GetWeakPtr()), |
| 173 | base::ThreadTaskRunnerHandle::Get())); |
[email protected] | cf0e7ee | 2012-07-11 00:49:17 | [diff] [blame] | 174 | reader_thread_.reset( |
| 175 | new base::DelegateSimpleThread(reader_thread_runner_.get(), |
| 176 | "ipc_channel_nacl reader thread")); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 177 | reader_thread_->Start(); |
| 178 | waiting_connect_ = false; |
| 179 | // If there were any messages queued before connection, send them. |
| 180 | ProcessOutgoingMessages(); |
skyostil | e687bdff | 2015-05-12 11:29:21 | [diff] [blame] | 181 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 182 | FROM_HERE, base::Bind(&ChannelNacl::CallOnChannelConnected, |
| 183 | weak_ptr_factory_.GetWeakPtr())); |
[email protected] | 7e3d752 | 2014-03-20 21:00:50 | [diff] [blame] | 184 | |
[email protected] | 5ce038b | 2012-06-06 18:14:56 | [diff] [blame] | 185 | return true; |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 186 | } |
| 187 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 188 | void ChannelNacl::Close() { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 189 | // For now, we assume that at shutdown, the reader thread will be woken with |
| 190 | // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we |
| 191 | // might simply be killed with no chance to clean up anyway :-). |
| 192 | // If untrusted code tries to close the channel prior to shutdown, it's likely |
| 193 | // to hang. |
| 194 | // TODO(dmichael): Can we do anything smarter here to make sure the reader |
| 195 | // thread wakes up and quits? |
| 196 | reader_thread_->Join(); |
| 197 | close(pipe_); |
| 198 | pipe_ = -1; |
| 199 | reader_thread_runner_.reset(); |
| 200 | reader_thread_.reset(); |
| 201 | read_queue_.clear(); |
| 202 | output_queue_.clear(); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 203 | } |
| 204 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 205 | bool ChannelNacl::Send(Message* message) { |
morrita | 81b17e0 | 2015-02-06 00:58:30 | [diff] [blame] | 206 | DCHECK(!message->HasAttachments()); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 207 | DVLOG(2) << "sending message @" << message << " on channel @" << this |
| 208 | << " with type " << message->type(); |
| 209 | scoped_ptr<Message> message_ptr(message); |
| 210 | |
| 211 | #ifdef IPC_MESSAGE_LOG_ENABLED |
[email protected] | 19d3a3e | 2012-06-11 18:18:33 | [diff] [blame] | 212 | Logging::GetInstance()->OnSendMessage(message_ptr.get(), ""); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 213 | #endif // IPC_MESSAGE_LOG_ENABLED |
| 214 | |
yuhaoz | 9b8157d | 2015-08-18 22:21:35 | [diff] [blame] | 215 | TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), |
| 216 | "ChannelNacl::Send", |
| 217 | message->header()->flags, |
| 218 | TRACE_EVENT_FLAG_FLOW_OUT); |
[email protected] | 19d3a3e | 2012-06-11 18:18:33 | [diff] [blame] | 219 | output_queue_.push_back(linked_ptr<Message>(message_ptr.release())); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 220 | if (!waiting_connect_) |
| 221 | return ProcessOutgoingMessages(); |
| 222 | |
| 223 | return true; |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 224 | } |
| 225 | |
erikchen | 27aa7d8 | 2015-06-16 21:21:04 | [diff] [blame] | 226 | AttachmentBroker* ChannelNacl::GetAttachmentBroker() { |
erikchen | 5708aae | 2015-09-14 17:45:12 | [diff] [blame] | 227 | return nullptr; |
erikchen | 27aa7d8 | 2015-06-16 21:21:04 | [diff] [blame] | 228 | } |
| 229 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 230 | void ChannelNacl::DidRecvMsg(scoped_ptr<MessageContents> contents) { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 231 | // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from |
| 232 | // the reader thread after Close is called. If so, we ignore it. |
| 233 | if (pipe_ == -1) |
| 234 | return; |
| 235 | |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 236 | linked_ptr<std::vector<char> > data(new std::vector<char>); |
| 237 | data->swap(contents->data); |
| 238 | read_queue_.push_back(data); |
| 239 | |
| 240 | input_fds_.insert(input_fds_.end(), |
| 241 | contents->fds.begin(), contents->fds.end()); |
| 242 | contents->fds.clear(); |
[email protected] | dbbe276b | 2012-06-06 21:47:57 | [diff] [blame] | 243 | |
| 244 | // In POSIX, we would be told when there are bytes to read by implementing |
| 245 | // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we |
| 246 | // instead know at this point because the reader thread posted some data to |
| 247 | // us. |
| 248 | ProcessIncomingMessages(); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 249 | } |
| 250 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 251 | void ChannelNacl::ReadDidFail() { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 252 | Close(); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 253 | } |
| 254 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 255 | bool ChannelNacl::CreatePipe( |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 256 | const IPC::ChannelHandle& channel_handle) { |
| 257 | DCHECK(pipe_ == -1); |
| 258 | |
| 259 | // There's one possible case in NaCl: |
| 260 | // 1) It's a channel wrapping a pipe that is given to us. |
| 261 | // We don't support these: |
| 262 | // 2) It's for a named channel. |
| 263 | // 3) It's for a client that we implement ourself. |
| 264 | // 4) It's the initial IPC channel. |
| 265 | |
| 266 | if (channel_handle.socket.fd == -1) { |
| 267 | NOTIMPLEMENTED(); |
| 268 | return false; |
| 269 | } |
| 270 | pipe_ = channel_handle.socket.fd; |
| 271 | return true; |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 272 | } |
| 273 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 274 | bool ChannelNacl::ProcessOutgoingMessages() { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 275 | DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
| 276 | // no connection? |
| 277 | if (output_queue_.empty()) |
| 278 | return true; |
| 279 | |
| 280 | if (pipe_ == -1) |
| 281 | return false; |
| 282 | |
| 283 | // Write out all the messages. The trusted implementation is guaranteed to not |
| 284 | // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg. |
| 285 | while (!output_queue_.empty()) { |
| 286 | linked_ptr<Message> msg = output_queue_.front(); |
| 287 | output_queue_.pop_front(); |
| 288 | |
morrita | 4b5c28e2 | 2015-01-14 21:17:06 | [diff] [blame] | 289 | int fds[MessageAttachmentSet::kMaxDescriptorsPerMessage]; |
erikchen | ae6d321 | 2015-10-10 02:43:49 | [diff] [blame] | 290 | const size_t num_fds = |
| 291 | msg->attachment_set()->num_non_brokerable_attachments(); |
morrita | 4b5c28e2 | 2015-01-14 21:17:06 | [diff] [blame] | 292 | DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage); |
| 293 | msg->attachment_set()->PeekDescriptors(fds); |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 294 | |
[email protected] | 18ff3c3 | 2013-06-05 23:37:11 | [diff] [blame] | 295 | NaClAbiNaClImcMsgIoVec iov = { |
| 296 | const_cast<void*>(msg->data()), msg->size() |
| 297 | }; |
| 298 | NaClAbiNaClImcMsgHdr msgh = { &iov, 1, fds, num_fds }; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 299 | ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0); |
| 300 | |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 301 | DCHECK(bytes_written); // The trusted side shouldn't return 0. |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 302 | if (bytes_written < 0) { |
| 303 | // The trusted side should only ever give us an error of EPIPE. We |
| 304 | // should never be interrupted, nor should we get EAGAIN. |
| 305 | DCHECK(errno == EPIPE); |
| 306 | Close(); |
| 307 | PLOG(ERROR) << "pipe_ error on " |
| 308 | << pipe_ |
| 309 | << " Currently writing message of size: " |
| 310 | << msg->size(); |
| 311 | return false; |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 312 | } else { |
erikchen | ae6d321 | 2015-10-10 02:43:49 | [diff] [blame] | 313 | msg->attachment_set()->CommitAllDescriptors(); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | // Message sent OK! |
| 317 | DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type() |
| 318 | << " on fd " << pipe_; |
| 319 | } |
| 320 | return true; |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 321 | } |
| 322 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 323 | void ChannelNacl::CallOnChannelConnected() { |
| 324 | listener()->OnChannelConnected(GetPeerPID()); |
[email protected] | 7e3d752 | 2014-03-20 21:00:50 | [diff] [blame] | 325 | } |
| 326 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 327 | ChannelNacl::ReadState ChannelNacl::ReadData( |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 328 | char* buffer, |
| 329 | int buffer_len, |
| 330 | int* bytes_read) { |
| 331 | *bytes_read = 0; |
| 332 | if (pipe_ == -1) |
| 333 | return READ_FAILED; |
| 334 | if (read_queue_.empty()) |
| 335 | return READ_PENDING; |
| 336 | while (!read_queue_.empty() && *bytes_read < buffer_len) { |
| 337 | linked_ptr<std::vector<char> > vec(read_queue_.front()); |
[email protected] | 74ca23f | 2012-09-24 04:49:10 | [diff] [blame] | 338 | size_t bytes_to_read = buffer_len - *bytes_read; |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 339 | if (vec->size() <= bytes_to_read) { |
| 340 | // We can read and discard the entire vector. |
| 341 | std::copy(vec->begin(), vec->end(), buffer + *bytes_read); |
| 342 | *bytes_read += vec->size(); |
| 343 | read_queue_.pop_front(); |
| 344 | } else { |
| 345 | // Read all the bytes we can and discard them from the front of the |
| 346 | // vector. (This can be slowish, since erase has to move the back of the |
| 347 | // vector to the front, but it's hopefully a temporary hack and it keeps |
| 348 | // the code simple). |
| 349 | std::copy(vec->begin(), vec->begin() + bytes_to_read, |
| 350 | buffer + *bytes_read); |
| 351 | vec->erase(vec->begin(), vec->begin() + bytes_to_read); |
| 352 | *bytes_read += bytes_to_read; |
| 353 | } |
| 354 | } |
| 355 | return READ_SUCCEEDED; |
[email protected] | fe5d406 | 2012-04-23 21:18:19 | [diff] [blame] | 356 | } |
| 357 | |
erikchen | de9412b8 | 2015-07-27 18:26:14 | [diff] [blame] | 358 | bool ChannelNacl::ShouldDispatchInputMessage(Message* msg) { |
| 359 | return true; |
| 360 | } |
| 361 | |
| 362 | bool ChannelNacl::GetNonBrokeredAttachments(Message* msg) { |
tfarina | 10a5c06 | 2015-09-04 18:47:57 | [diff] [blame] | 363 | uint16_t header_fds = msg->header()->num_fds; |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 364 | CHECK(header_fds == input_fds_.size()); |
| 365 | if (header_fds == 0) |
| 366 | return true; // Nothing to do. |
| 367 | |
| 368 | // The shenaniganery below with &foo.front() requires input_fds_ to have |
| 369 | // contiguous underlying storage (such as a simple array or a std::vector). |
| 370 | // This is why the header warns not to make input_fds_ a deque<>. |
morrita | 4b5c28e2 | 2015-01-14 21:17:06 | [diff] [blame] | 371 | msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds); |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 372 | input_fds_.clear(); |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 373 | return true; |
[email protected] | fe5d406 | 2012-04-23 21:18:19 | [diff] [blame] | 374 | } |
| 375 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 376 | bool ChannelNacl::DidEmptyInputBuffers() { |
[email protected] | ff79fa2 | 2012-07-10 17:26:03 | [diff] [blame] | 377 | // When the input data buffer is empty, the fds should be too. |
| 378 | return input_fds_.empty(); |
[email protected] | fe5d406 | 2012-04-23 21:18:19 | [diff] [blame] | 379 | } |
| 380 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 381 | void ChannelNacl::HandleInternalMessage(const Message& msg) { |
[email protected] | 4e8f0a76 | 2012-05-31 19:37:54 | [diff] [blame] | 382 | // The trusted side IPC::Channel should handle the "hello" handshake; we |
| 383 | // should not receive the "Hello" message. |
| 384 | NOTREACHED(); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 385 | } |
| 386 | |
erikchen | 3c175a3 | 2015-07-28 23:16:48 | [diff] [blame] | 387 | base::ProcessId ChannelNacl::GetSenderPID() { |
| 388 | // The untrusted side of the IPC::Channel should never have to worry about |
| 389 | // sender's process id. |
| 390 | return base::kNullProcessId; |
| 391 | } |
| 392 | |
erikchen | 8c73f83 | 2015-07-30 22:26:08 | [diff] [blame] | 393 | bool ChannelNacl::IsAttachmentBrokerEndpoint() { |
| 394 | return is_attachment_broker_endpoint(); |
| 395 | } |
| 396 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 397 | // Channel's methods |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 398 | |
[email protected] | 2f60c9b | 2014-06-06 20:13:51 | [diff] [blame] | 399 | // static |
erikchen | 27aa7d8 | 2015-06-16 21:21:04 | [diff] [blame] | 400 | scoped_ptr<Channel> Channel::Create(const IPC::ChannelHandle& channel_handle, |
| 401 | Mode mode, |
erikchen | 30dc281 | 2015-09-24 03:26:38 | [diff] [blame] | 402 | Listener* listener) { |
| 403 | return scoped_ptr<Channel>(new ChannelNacl(channel_handle, mode, listener)); |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 404 | } |
| 405 | |
[email protected] | 456b0ea | 2012-03-30 19:57:22 | [diff] [blame] | 406 | } // namespace IPC |