blob: db8c96116e3e71bf10e19203448f8ce1c9722659 [file] [log] [blame]
[email protected]a7c03d4f32012-01-24 02:36:051// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]946d1b22009-07-22 23:57:215#include "ipc/ipc_channel_win.h"
[email protected]c1afbd2c2008-10-13 19:19:366
initial.commit09911bf2008-07-26 23:55:297#include <windows.h>
initial.commit09911bf2008-07-26 23:55:298
[email protected]5be7da242009-11-20 23:16:269#include "base/auto_reset.h"
[email protected]72b6f8e22011-11-12 21:16:4110#include "base/bind.h"
[email protected]c1afbd2c2008-10-13 19:19:3611#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/logging.h"
[email protected]7edae3d02012-12-17 20:23:4713#include "base/pickle.h"
[email protected]e66ef602013-07-24 05:15:2414#include "base/process/process_handle.h"
[email protected]5c41e6e12012-03-17 02:20:4615#include "base/rand_util.h"
[email protected]4aa794a12013-06-11 06:32:1816#include "base/strings/string_number_conversions.h"
[email protected]906265872013-06-07 22:40:4517#include "base/strings/utf_string_conversions.h"
[email protected]327e52b2012-06-25 21:11:3618#include "base/threading/thread_checker.h"
[email protected]b90d7e802011-01-09 16:32:2019#include "base/win/scoped_handle.h"
[email protected]0ee990682012-11-17 19:20:0520#include "ipc/ipc_listener.h"
[email protected]946d1b22009-07-22 23:57:2121#include "ipc/ipc_logging.h"
22#include "ipc/ipc_message_utils.h"
initial.commit09911bf2008-07-26 23:55:2923
[email protected]2d0faf12014-06-27 04:50:4324namespace {
25
26enum DebugFlags {
27 INIT_DONE = 1 << 0,
28 CALLED_CONNECT = 1 << 1,
29 PENDING_CONNECT = 1 << 2,
30 CONNECT_COMPLETED = 1 << 3,
31 PIPE_CONNECTED = 1 << 4,
32 WRITE_MSG = 1 << 5,
33 READ_MSG = 1 << 6,
34 WRITE_COMPLETED = 1 << 7,
35 READ_COMPLETED = 1 << 8,
36 CLOSED = 1 << 9,
37 WAIT_FOR_READ = 1 << 10,
38 WAIT_FOR_WRITE = 1 << 11,
39 WAIT_FOR_READ_COMPLETE = 1 << 12,
40 WAIT_FOR_WRITE_COMPLETE = 1 << 13
41};
42
43} // namespace
44
initial.commit09911bf2008-07-26 23:55:2945namespace IPC {
[email protected]935aa542010-10-15 01:59:1546
[email protected]2f60c9b2014-06-06 20:13:5147ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
[email protected]17b89142008-11-07 21:52:1548 memset(&context.overlapped, 0, sizeof(context.overlapped));
49 context.handler = channel;
initial.commit09911bf2008-07-26 23:55:2950}
51
[email protected]2f60c9b2014-06-06 20:13:5152ChannelWin::State::~State() {
53 COMPILE_ASSERT(!offsetof(ChannelWin::State, context),
[email protected]514411fc2008-12-10 22:28:1154 starts_with_io_context);
initial.commit09911bf2008-07-26 23:55:2955}
56
[email protected]2f60c9b2014-06-06 20:13:5157ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
[email protected]2d0faf12014-06-27 04:50:4358 Mode mode, Listener* listener)
[email protected]d805c6a2012-03-08 12:30:2859 : ChannelReader(listener),
[email protected]ba2194d2013-04-26 19:51:3060 input_state_(this),
61 output_state_(this),
[email protected]0a6fc4b2012-04-05 02:38:3462 peer_pid_(base::kNullProcessId),
[email protected]1707726c2011-02-03 20:35:0963 waiting_connect_(mode & MODE_SERVER_FLAG),
[email protected]c1afbd2c2008-10-13 19:19:3664 processing_incoming_(false),
[email protected]2d0faf12014-06-27 04:50:4365 validate_client_(false),
[email protected]65727eb2014-07-31 12:24:2966 writing_(false),
[email protected]2d0faf12014-06-27 04:50:4367 debug_flags_(0),
rvargas431ce732014-09-16 02:44:1568 write_error_(0),
69 last_write_error_(0),
70 write_size_(0),
[email protected]65727eb2014-07-31 12:24:2971 client_secret_(0),
72 weak_factory_(this) {
[email protected]c2391b82011-05-06 17:39:0773 CreatePipe(channel_handle, mode);
initial.commit09911bf2008-07-26 23:55:2974}
75
[email protected]2f60c9b2014-06-06 20:13:5176ChannelWin::~ChannelWin() {
[email protected]601858c02010-09-01 17:08:2077 Close();
78}
79
[email protected]2f60c9b2014-06-06 20:13:5180void ChannelWin::Close() {
[email protected]c1e4bff32009-01-29 00:07:0681 if (thread_check_.get()) {
82 DCHECK(thread_check_->CalledOnValidThread());
83 }
[email protected]2d0faf12014-06-27 04:50:4384 debug_flags_ |= CLOSED;
[email protected]c1e4bff32009-01-29 00:07:0685
[email protected]74f87acf22009-10-14 22:10:4086 if (input_state_.is_pending || output_state_.is_pending)
rvargas8c2d75c2014-09-26 19:50:2687 CancelIo(pipe_.Get());
[email protected]ee78622d2008-10-13 21:25:5088
[email protected]17b89142008-11-07 21:52:1589 // Closing the handle at this point prevents us from issuing more requests
90 // form OnIOCompleted().
rvargas8c2d75c2014-09-26 19:50:2691 if (pipe_.IsValid())
92 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:2993
[email protected]2d0faf12014-06-27 04:50:4394 if (input_state_.is_pending)
95 debug_flags_ |= WAIT_FOR_READ;
96
97 if (output_state_.is_pending)
98 debug_flags_ |= WAIT_FOR_WRITE;
99
[email protected]17b89142008-11-07 21:52:15100 // Make sure all IO has completed.
101 base::Time start = base::Time::Now();
102 while (input_state_.is_pending || output_state_.is_pending) {
[email protected]fd0a773a2013-04-30 20:55:03103 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
[email protected]17b89142008-11-07 21:52:15104 }
[email protected]17b89142008-11-07 21:52:15105
initial.commit09911bf2008-07-26 23:55:29106 while (!output_queue_.empty()) {
107 Message* m = output_queue_.front();
108 output_queue_.pop();
109 delete m;
110 }
111}
112
[email protected]2f60c9b2014-06-06 20:13:51113bool ChannelWin::Send(Message* message) {
[email protected]c1e4bff32009-01-29 00:07:06114 DCHECK(thread_check_->CalledOnValidThread());
[email protected]2a9d601b2010-10-19 23:50:00115 DVLOG(2) << "sending message @" << message << " on channel @" << this
116 << " with type " << message->type()
117 << " (" << output_queue_.size() << " in queue)";
initial.commit09911bf2008-07-26 23:55:29118
119#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]8e8bb6d2010-12-13 08:18:55120 Logging::GetInstance()->OnSendMessage(message, "");
initial.commit09911bf2008-07-26 23:55:29121#endif
122
[email protected]2c391df2012-09-18 03:41:29123 message->TraceMessageBegin();
initial.commit09911bf2008-07-26 23:55:29124 output_queue_.push(message);
125 // ensure waiting to write
126 if (!waiting_connect_) {
127 if (!output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36128 if (!ProcessOutgoingMessages(NULL, 0))
initial.commit09911bf2008-07-26 23:55:29129 return false;
initial.commit09911bf2008-07-26 23:55:29130 }
131 }
132
133 return true;
134}
135
[email protected]2f60c9b2014-06-06 20:13:51136base::ProcessId ChannelWin::GetPeerPID() const {
137 return peer_pid_;
138}
139
[email protected]64860882014-08-04 23:44:17140base::ProcessId ChannelWin::GetSelfPID() const {
141 return GetCurrentProcessId();
142}
143
[email protected]313c00e52011-08-09 06:46:06144// static
[email protected]2f60c9b2014-06-06 20:13:51145bool ChannelWin::IsNamedServerInitialized(
[email protected]313c00e52011-08-09 06:46:06146 const std::string& channel_id) {
[email protected]5c41e6e12012-03-17 02:20:46147 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
[email protected]313c00e52011-08-09 06:46:06148 return true;
149 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
150 // connection.
151 return GetLastError() == ERROR_SEM_TIMEOUT;
152}
153
[email protected]2f60c9b2014-06-06 20:13:51154ChannelWin::ReadState ChannelWin::ReadData(
[email protected]215f6fd2012-03-03 08:55:45155 char* buffer,
156 int buffer_len,
157 int* /* bytes_read */) {
rvargas8c2d75c2014-09-26 19:50:26158 if (!pipe_.IsValid())
[email protected]215f6fd2012-03-03 08:55:45159 return READ_FAILED;
160
[email protected]2d0faf12014-06-27 04:50:43161 debug_flags_ |= READ_MSG;
[email protected]215f6fd2012-03-03 08:55:45162 DWORD bytes_read = 0;
rvargas8c2d75c2014-09-26 19:50:26163 BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len,
[email protected]215f6fd2012-03-03 08:55:45164 &bytes_read, &input_state_.context.overlapped);
165 if (!ok) {
166 DWORD err = GetLastError();
167 if (err == ERROR_IO_PENDING) {
168 input_state_.is_pending = true;
169 return READ_PENDING;
170 }
171 LOG(ERROR) << "pipe error: " << err;
172 return READ_FAILED;
173 }
174
175 // We could return READ_SUCCEEDED here. But the way that this code is
176 // structured we instead go back to the message loop. Our completion port
177 // will be signalled even in the "synchronously completed" state.
178 //
179 // This allows us to potentially process some outgoing messages and
180 // interleave other work on this thread when we're getting hammered with
181 // input messages. Potentially, this could be tuned to be more efficient
182 // with some testing.
183 input_state_.is_pending = true;
184 return READ_PENDING;
185}
186
[email protected]2f60c9b2014-06-06 20:13:51187bool ChannelWin::WillDispatchInputMessage(Message* msg) {
[email protected]05908782012-04-03 08:49:43188 // Make sure we get a hello when client validation is required.
189 if (validate_client_)
190 return IsHelloMessage(*msg);
[email protected]215f6fd2012-03-03 08:55:45191 return true;
192}
193
[email protected]2f60c9b2014-06-06 20:13:51194void ChannelWin::HandleInternalMessage(const Message& msg) {
[email protected]dc875dc2013-10-15 00:07:00195 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
[email protected]215f6fd2012-03-03 08:55:45196 // The hello message contains one parameter containing the PID.
[email protected]7edae3d02012-12-17 20:23:47197 PickleIterator it(msg);
198 int32 claimed_pid;
199 bool failed = !it.ReadInt(&claimed_pid);
200
201 if (!failed && validate_client_) {
202 int32 secret;
203 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true;
204 }
205
206 if (failed) {
[email protected]5c41e6e12012-03-17 02:20:46207 NOTREACHED();
[email protected]5c41e6e12012-03-17 02:20:46208 Close();
209 listener()->OnChannelError();
210 return;
211 }
[email protected]7edae3d02012-12-17 20:23:47212
[email protected]0a6fc4b2012-04-05 02:38:34213 peer_pid_ = claimed_pid;
[email protected]7edae3d02012-12-17 20:23:47214 // Validation completed.
[email protected]05908782012-04-03 08:49:43215 validate_client_ = false;
[email protected]5c41e6e12012-03-17 02:20:46216 listener()->OnChannelConnected(claimed_pid);
[email protected]215f6fd2012-03-03 08:55:45217}
218
[email protected]2f60c9b2014-06-06 20:13:51219bool ChannelWin::DidEmptyInputBuffers() {
[email protected]d805c6a2012-03-08 12:30:28220 // We don't need to do anything here.
[email protected]215f6fd2012-03-03 08:55:45221 return true;
222}
223
[email protected]313c00e52011-08-09 06:46:06224// static
[email protected]2f60c9b2014-06-06 20:13:51225const base::string16 ChannelWin::PipeName(
[email protected]5c41e6e12012-03-17 02:20:46226 const std::string& channel_id, int32* secret) {
[email protected]c2391b82011-05-06 17:39:07227 std::string name("\\\\.\\pipe\\chrome.");
[email protected]5c41e6e12012-03-17 02:20:46228
229 // Prevent the shared secret from ending up in the pipe name.
230 size_t index = channel_id.find_first_of('\\');
231 if (index != std::string::npos) {
232 if (secret) // Retrieve the secret if asked for.
233 base::StringToInt(channel_id.substr(index + 1), secret);
thestige5c64d92014-11-07 01:19:24234 return base::ASCIIToUTF16(name.append(channel_id.substr(0, index - 1)));
[email protected]5c41e6e12012-03-17 02:20:46235 }
236
237 // This case is here to support predictable named pipes in tests.
238 if (secret)
239 *secret = 0;
thestige5c64d92014-11-07 01:19:24240 return base::ASCIIToUTF16(name.append(channel_id));
initial.commit09911bf2008-07-26 23:55:29241}
242
[email protected]2f60c9b2014-06-06 20:13:51243bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
rvargas8c2d75c2014-09-26 19:50:26244 Mode mode) {
245 DCHECK(!pipe_.IsValid());
[email protected]905cda812013-12-20 09:04:55246 base::string16 pipe_name;
[email protected]a7c03d4f32012-01-24 02:36:05247 // If we already have a valid pipe for channel just copy it.
248 if (channel_handle.pipe.handle) {
rvargas8c2d75c2014-09-26 19:50:26249 // TODO(rvargas) crbug.com/415294: ChannelHandle should either go away in
250 // favor of two independent entities (name/file), or it should be a move-
251 // only type with a base::File member. In any case, this code should not
252 // call DuplicateHandle.
[email protected]a7c03d4f32012-01-24 02:36:05253 DCHECK(channel_handle.name.empty());
254 pipe_name = L"Not Available"; // Just used for LOG
255 // Check that the given pipe confirms to the specified mode. We can
256 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the
257 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0.
258 DWORD flags = 0;
259 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL);
260 DCHECK(!(flags & PIPE_TYPE_MESSAGE));
261 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) ||
262 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) {
263 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode;
264 return false;
265 }
rvargas8c2d75c2014-09-26 19:50:26266 HANDLE local_handle;
[email protected]a7c03d4f32012-01-24 02:36:05267 if (!DuplicateHandle(GetCurrentProcess(),
268 channel_handle.pipe.handle,
269 GetCurrentProcess(),
rvargas8c2d75c2014-09-26 19:50:26270 &local_handle,
[email protected]a7c03d4f32012-01-24 02:36:05271 0,
272 FALSE,
273 DUPLICATE_SAME_ACCESS)) {
274 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError();
275 return false;
276 }
rvargas8c2d75c2014-09-26 19:50:26277 pipe_.Set(local_handle);
[email protected]a7c03d4f32012-01-24 02:36:05278 } else if (mode & MODE_SERVER_FLAG) {
279 DCHECK(!channel_handle.pipe.handle);
280 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
281 FILE_FLAG_FIRST_PIPE_INSTANCE;
[email protected]5c41e6e12012-03-17 02:20:46282 pipe_name = PipeName(channel_handle.name, &client_secret_);
283 validate_client_ = !!client_secret_;
rvargas8c2d75c2014-09-26 19:50:26284 pipe_.Set(CreateNamedPipeW(pipe_name.c_str(),
285 open_mode,
286 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
287 1,
288 Channel::kReadBufferSize,
289 Channel::kReadBufferSize,
290 5000,
291 NULL));
[email protected]1707726c2011-02-03 20:35:09292 } else if (mode & MODE_CLIENT_FLAG) {
[email protected]a7c03d4f32012-01-24 02:36:05293 DCHECK(!channel_handle.pipe.handle);
[email protected]5c41e6e12012-03-17 02:20:46294 pipe_name = PipeName(channel_handle.name, &client_secret_);
rvargas8c2d75c2014-09-26 19:50:26295 pipe_.Set(CreateFileW(pipe_name.c_str(),
296 GENERIC_READ | GENERIC_WRITE,
297 0,
298 NULL,
299 OPEN_EXISTING,
300 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
301 FILE_FLAG_OVERLAPPED,
302 NULL));
[email protected]1707726c2011-02-03 20:35:09303 } else {
304 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29305 }
[email protected]a7c03d4f32012-01-24 02:36:05306
rvargas8c2d75c2014-09-26 19:50:26307 if (!pipe_.IsValid()) {
initial.commit09911bf2008-07-26 23:55:29308 // If this process is being closed, the pipe may be gone already.
[email protected]8398bf12014-06-26 21:11:34309 PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in "
310 << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode";
initial.commit09911bf2008-07-26 23:55:29311 return false;
312 }
313
314 // Create the Hello message to be sent when Connect is called
315 scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
[email protected]753bb252013-11-04 22:28:12316 HELLO_MESSAGE_TYPE,
317 IPC::Message::PRIORITY_NORMAL));
[email protected]5c41e6e12012-03-17 02:20:46318
319 // Don't send the secret to the untrusted process, and don't send a secret
320 // if the value is zero (for IPC backwards compatability).
321 int32 secret = validate_client_ ? 0 : client_secret_;
322 if (!m->WriteInt(GetCurrentProcessId()) ||
323 (secret && !m->WriteUInt32(secret))) {
rvargas8c2d75c2014-09-26 19:50:26324 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:29325 return false;
326 }
327
[email protected]2d0faf12014-06-27 04:50:43328 debug_flags_ |= INIT_DONE;
329
initial.commit09911bf2008-07-26 23:55:29330 output_queue_.push(m.release());
331 return true;
332}
333
[email protected]2f60c9b2014-06-06 20:13:51334bool ChannelWin::Connect() {
[email protected]19340722009-08-17 19:53:25335 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
initial.commit09911bf2008-07-26 23:55:29336
[email protected]c1e4bff32009-01-29 00:07:06337 if (!thread_check_.get())
[email protected]327e52b2012-06-25 21:11:36338 thread_check_.reset(new base::ThreadChecker());
[email protected]c1e4bff32009-01-29 00:07:06339
rvargas8c2d75c2014-09-26 19:50:26340 if (!pipe_.IsValid())
initial.commit09911bf2008-07-26 23:55:29341 return false;
342
rvargas8c2d75c2014-09-26 19:50:26343 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_.Get(), this);
[email protected]c1afbd2c2008-10-13 19:19:36344
initial.commit09911bf2008-07-26 23:55:29345 // Check to see if there is a client connected to our pipe...
346 if (waiting_connect_)
347 ProcessConnection();
348
349 if (!input_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36350 // Complete setup asynchronously. By not setting input_state_.is_pending
351 // to true, we indicate to OnIOCompleted that this is the special
352 // initialization signal.
[email protected]fd0a773a2013-04-30 20:55:03353 base::MessageLoopForIO::current()->PostTask(
354 FROM_HERE,
[email protected]2f60c9b2014-06-06 20:13:51355 base::Bind(&ChannelWin::OnIOCompleted,
[email protected]fd0a773a2013-04-30 20:55:03356 weak_factory_.GetWeakPtr(),
357 &input_state_.context,
358 0,
359 0));
initial.commit09911bf2008-07-26 23:55:29360 }
361
362 if (!waiting_connect_)
[email protected]c1afbd2c2008-10-13 19:19:36363 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29364 return true;
365}
366
[email protected]2f60c9b2014-06-06 20:13:51367bool ChannelWin::ProcessConnection() {
[email protected]c1e4bff32009-01-29 00:07:06368 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15369 if (input_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36370 input_state_.is_pending = false;
initial.commit09911bf2008-07-26 23:55:29371
372 // Do we have a client connected to our pipe?
rvargas8c2d75c2014-09-26 19:50:26373 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15374 return false;
375
rvargas8c2d75c2014-09-26 19:50:26376 BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped);
[email protected]2d0faf12014-06-27 04:50:43377 debug_flags_ |= CALLED_CONNECT;
initial.commit09911bf2008-07-26 23:55:29378
379 DWORD err = GetLastError();
380 if (ok) {
381 // Uhm, the API documentation says that this function should never
382 // return success when used in overlapped mode.
383 NOTREACHED();
384 return false;
385 }
386
387 switch (err) {
388 case ERROR_IO_PENDING:
389 input_state_.is_pending = true;
[email protected]2d0faf12014-06-27 04:50:43390 debug_flags_ |= PENDING_CONNECT;
initial.commit09911bf2008-07-26 23:55:29391 break;
392 case ERROR_PIPE_CONNECTED:
[email protected]2d0faf12014-06-27 04:50:43393 debug_flags_ |= PIPE_CONNECTED;
initial.commit09911bf2008-07-26 23:55:29394 waiting_connect_ = false;
395 break;
[email protected]20aa32c2009-07-14 22:25:49396 case ERROR_NO_DATA:
397 // The pipe is being closed.
398 return false;
initial.commit09911bf2008-07-26 23:55:29399 default:
400 NOTREACHED();
401 return false;
402 }
403
404 return true;
405}
406
[email protected]2f60c9b2014-06-06 20:13:51407bool ChannelWin::ProcessOutgoingMessages(
[email protected]fd0a773a2013-04-30 20:55:03408 base::MessageLoopForIO::IOContext* context,
[email protected]514411fc2008-12-10 22:28:11409 DWORD bytes_written) {
initial.commit09911bf2008-07-26 23:55:29410 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
411 // no connection?
[email protected]c1e4bff32009-01-29 00:07:06412 DCHECK(thread_check_->CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29413
414 if (output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36415 DCHECK(context);
initial.commit09911bf2008-07-26 23:55:29416 output_state_.is_pending = false;
[email protected]c1afbd2c2008-10-13 19:19:36417 if (!context || bytes_written == 0) {
initial.commit09911bf2008-07-26 23:55:29418 DWORD err = GetLastError();
419 LOG(ERROR) << "pipe error: " << err;
420 return false;
421 }
[email protected]c1afbd2c2008-10-13 19:19:36422 // Message was sent.
[email protected]88ecb5f52014-01-21 14:29:36423 CHECK(!output_queue_.empty());
initial.commit09911bf2008-07-26 23:55:29424 Message* m = output_queue_.front();
425 output_queue_.pop();
426 delete m;
427 }
428
[email protected]17b89142008-11-07 21:52:15429 if (output_queue_.empty())
430 return true;
431
rvargas8c2d75c2014-09-26 19:50:26432 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15433 return false;
434
435 // Write to pipe...
436 Message* m = output_queue_.front();
[email protected]8a861402011-01-28 19:59:11437 DCHECK(m->size() <= INT_MAX);
[email protected]2d0faf12014-06-27 04:50:43438 debug_flags_ |= WRITE_MSG;
[email protected]65727eb2014-07-31 12:24:29439 CHECK(!writing_);
440 writing_ = true;
rvargas431ce732014-09-16 02:44:15441 write_size_ = static_cast<uint32>(m->size());
442 write_error_ = 0;
rvargas8c2d75c2014-09-26 19:50:26443 BOOL ok = WriteFile(pipe_.Get(),
[email protected]17b89142008-11-07 21:52:15444 m->data(),
rvargas431ce732014-09-16 02:44:15445 write_size_,
446 NULL,
[email protected]17b89142008-11-07 21:52:15447 &output_state_.context.overlapped);
448 if (!ok) {
rvargas431ce732014-09-16 02:44:15449 write_error_ = GetLastError();
450 if (write_error_ == ERROR_IO_PENDING) {
[email protected]17b89142008-11-07 21:52:15451 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29452
[email protected]2a9d601b2010-10-19 23:50:00453 DVLOG(2) << "sent pending message @" << m << " on channel @" << this
454 << " with type " << m->type();
initial.commit09911bf2008-07-26 23:55:29455
[email protected]17b89142008-11-07 21:52:15456 return true;
initial.commit09911bf2008-07-26 23:55:29457 }
[email protected]65727eb2014-07-31 12:24:29458 writing_ = false;
rvargas431ce732014-09-16 02:44:15459 last_write_error_ = write_error_;
460 LOG(ERROR) << "pipe error: " << write_error_;
[email protected]17b89142008-11-07 21:52:15461 return false;
initial.commit09911bf2008-07-26 23:55:29462 }
463
[email protected]2a9d601b2010-10-19 23:50:00464 DVLOG(2) << "sent message @" << m << " on channel @" << this
465 << " with type " << m->type();
[email protected]17b89142008-11-07 21:52:15466
467 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29468 return true;
469}
470
[email protected]2f60c9b2014-06-06 20:13:51471void ChannelWin::OnIOCompleted(
[email protected]fd0a773a2013-04-30 20:55:03472 base::MessageLoopForIO::IOContext* context,
473 DWORD bytes_transfered,
474 DWORD error) {
[email protected]215f6fd2012-03-03 08:55:45475 bool ok = true;
[email protected]c1e4bff32009-01-29 00:07:06476 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15477 if (context == &input_state_.context) {
initial.commit09911bf2008-07-26 23:55:29478 if (waiting_connect_) {
[email protected]2d0faf12014-06-27 04:50:43479 debug_flags_ |= CONNECT_COMPLETED;
[email protected]17b89142008-11-07 21:52:15480 if (!ProcessConnection())
481 return;
initial.commit09911bf2008-07-26 23:55:29482 // We may have some messages queued up to send...
483 if (!output_queue_.empty() && !output_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36484 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29485 if (input_state_.is_pending)
486 return;
487 // else, fall-through and look for incoming messages...
488 }
[email protected]215f6fd2012-03-03 08:55:45489
490 // We don't support recursion through OnMessageReceived yet!
initial.commit09911bf2008-07-26 23:55:29491 DCHECK(!processing_incoming_);
[email protected]997ec9f2012-11-21 04:44:14492 base::AutoReset<bool> auto_reset_processing_incoming(
493 &processing_incoming_, true);
[email protected]215f6fd2012-03-03 08:55:45494
495 // Process the new data.
496 if (input_state_.is_pending) {
497 // This is the normal case for everything except the initialization step.
[email protected]2d0faf12014-06-27 04:50:43498 debug_flags_ |= READ_COMPLETED;
499 if (debug_flags_ & WAIT_FOR_READ) {
500 CHECK(!(debug_flags_ & WAIT_FOR_READ_COMPLETE));
501 debug_flags_ |= WAIT_FOR_READ_COMPLETE;
502 }
[email protected]215f6fd2012-03-03 08:55:45503 input_state_.is_pending = false;
504 if (!bytes_transfered)
505 ok = false;
rvargas8c2d75c2014-09-26 19:50:26506 else if (pipe_.IsValid())
[email protected]215f6fd2012-03-03 08:55:45507 ok = AsyncReadComplete(bytes_transfered);
508 } else {
509 DCHECK(!bytes_transfered);
510 }
511
512 // Request more data.
513 if (ok)
514 ok = ProcessIncomingMessages();
initial.commit09911bf2008-07-26 23:55:29515 } else {
[email protected]17b89142008-11-07 21:52:15516 DCHECK(context == &output_state_.context);
[email protected]65727eb2014-07-31 12:24:29517 CHECK(writing_);
518 CHECK(output_state_.is_pending);
519 writing_ = false;
[email protected]2d0faf12014-06-27 04:50:43520 debug_flags_ |= WRITE_COMPLETED;
521 if (debug_flags_ & WAIT_FOR_WRITE) {
522 CHECK(!(debug_flags_ & WAIT_FOR_WRITE_COMPLETE));
523 debug_flags_ |= WAIT_FOR_WRITE_COMPLETE;
524 }
[email protected]c1afbd2c2008-10-13 19:19:36525 ok = ProcessOutgoingMessages(context, bytes_transfered);
initial.commit09911bf2008-07-26 23:55:29526 }
rvargas8c2d75c2014-09-26 19:50:26527 if (!ok && pipe_.IsValid()) {
[email protected]17b89142008-11-07 21:52:15528 // We don't want to re-enter Close().
initial.commit09911bf2008-07-26 23:55:29529 Close();
[email protected]d805c6a2012-03-08 12:30:28530 listener()->OnChannelError();
initial.commit09911bf2008-07-26 23:55:29531 }
532}
533
[email protected]514411fc2008-12-10 22:28:11534//------------------------------------------------------------------------------
[email protected]2f60c9b2014-06-06 20:13:51535// Channel's methods
[email protected]514411fc2008-12-10 22:28:11536
[email protected]2f60c9b2014-06-06 20:13:51537// static
538scoped_ptr<Channel> Channel::Create(
539 const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
540 return scoped_ptr<Channel>(
541 new ChannelWin(channel_handle, mode, listener));
[email protected]514411fc2008-12-10 22:28:11542}
543
[email protected]313c00e52011-08-09 06:46:06544// static
545bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
[email protected]2f60c9b2014-06-06 20:13:51546 return ChannelWin::IsNamedServerInitialized(channel_id);
[email protected]313c00e52011-08-09 06:46:06547}
548
[email protected]5c41e6e12012-03-17 02:20:46549// static
550std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
551 // Windows pipes can be enumerated by low-privileged processes. So, we
552 // append a strong random value after the \ character. This value is not
553 // included in the pipe name, but sent as part of the client hello, to
554 // hijacking the pipe name to spoof the client.
555
556 std::string id = prefix;
557 if (!id.empty())
558 id.append(".");
559
560 int secret;
561 do { // Guarantee we get a non-zero value.
562 secret = base::RandInt(0, std::numeric_limits<int>::max());
563 } while (secret == 0);
564
565 id.append(GenerateUniqueRandomChannelID());
566 return id.append(base::StringPrintf("\\%d", secret));
567}
568
[email protected]514411fc2008-12-10 22:28:11569} // namespace IPC