OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "ipc/ipc_channel_win.h" | 5 #include "ipc/ipc_channel_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/pickle.h" | 13 #include "base/pickle.h" |
14 #include "base/process/process_handle.h" | 14 #include "base/process/process_handle.h" |
15 #include "base/rand_util.h" | 15 #include "base/rand_util.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "base/threading/thread_checker.h" | 18 #include "base/threading/thread_checker.h" |
19 #include "base/win/scoped_handle.h" | 19 #include "base/win/scoped_handle.h" |
20 #include "ipc/ipc_listener.h" | 20 #include "ipc/ipc_listener.h" |
21 #include "ipc/ipc_logging.h" | 21 #include "ipc/ipc_logging.h" |
22 #include "ipc/ipc_message_utils.h" | 22 #include "ipc/ipc_message_utils.h" |
23 | 23 |
24 namespace IPC { | 24 namespace IPC { |
25 | 25 |
26 Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) { | 26 ChannelWin::State::State(ChannelWin* channel) : is_pending(false) { |
27 memset(&context.overlapped, 0, sizeof(context.overlapped)); | 27 memset(&context.overlapped, 0, sizeof(context.overlapped)); |
28 context.handler = channel; | 28 context.handler = channel; |
29 } | 29 } |
30 | 30 |
31 Channel::ChannelImpl::State::~State() { | 31 ChannelWin::State::~State() { |
32 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), | 32 COMPILE_ASSERT(!offsetof(ChannelWin::State, context), |
33 starts_with_io_context); | 33 starts_with_io_context); |
34 } | 34 } |
35 | 35 |
36 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, | 36 ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle, |
37 Mode mode, Listener* listener) | 37 Mode mode, Listener* listener) |
38 : ChannelReader(listener), | 38 : ChannelReader(listener), |
39 input_state_(this), | 39 input_state_(this), |
40 output_state_(this), | 40 output_state_(this), |
41 pipe_(INVALID_HANDLE_VALUE), | 41 pipe_(INVALID_HANDLE_VALUE), |
42 peer_pid_(base::kNullProcessId), | 42 peer_pid_(base::kNullProcessId), |
43 waiting_connect_(mode & MODE_SERVER_FLAG), | 43 waiting_connect_(mode & MODE_SERVER_FLAG), |
44 processing_incoming_(false), | 44 processing_incoming_(false), |
45 weak_factory_(this), | 45 weak_factory_(this), |
46 client_secret_(0), | 46 client_secret_(0), |
47 validate_client_(false) { | 47 validate_client_(false) { |
48 CreatePipe(channel_handle, mode); | 48 CreatePipe(channel_handle, mode); |
49 } | 49 } |
50 | 50 |
51 Channel::ChannelImpl::~ChannelImpl() { | 51 ChannelWin::~ChannelWin() { |
52 Close(); | 52 Close(); |
53 } | 53 } |
54 | 54 |
55 void Channel::ChannelImpl::Close() { | 55 void ChannelWin::Close() { |
56 if (thread_check_.get()) { | 56 if (thread_check_.get()) { |
57 DCHECK(thread_check_->CalledOnValidThread()); | 57 DCHECK(thread_check_->CalledOnValidThread()); |
58 } | 58 } |
59 | 59 |
60 if (input_state_.is_pending || output_state_.is_pending) | 60 if (input_state_.is_pending || output_state_.is_pending) |
61 CancelIo(pipe_); | 61 CancelIo(pipe_); |
62 | 62 |
63 // Closing the handle at this point prevents us from issuing more requests | 63 // Closing the handle at this point prevents us from issuing more requests |
64 // form OnIOCompleted(). | 64 // form OnIOCompleted(). |
65 if (pipe_ != INVALID_HANDLE_VALUE) { | 65 if (pipe_ != INVALID_HANDLE_VALUE) { |
66 CloseHandle(pipe_); | 66 CloseHandle(pipe_); |
67 pipe_ = INVALID_HANDLE_VALUE; | 67 pipe_ = INVALID_HANDLE_VALUE; |
68 } | 68 } |
69 | 69 |
70 // Make sure all IO has completed. | 70 // Make sure all IO has completed. |
71 base::Time start = base::Time::Now(); | 71 base::Time start = base::Time::Now(); |
72 while (input_state_.is_pending || output_state_.is_pending) { | 72 while (input_state_.is_pending || output_state_.is_pending) { |
73 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); | 73 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); |
74 } | 74 } |
75 | 75 |
76 while (!output_queue_.empty()) { | 76 while (!output_queue_.empty()) { |
77 Message* m = output_queue_.front(); | 77 Message* m = output_queue_.front(); |
78 output_queue_.pop(); | 78 output_queue_.pop(); |
79 delete m; | 79 delete m; |
80 } | 80 } |
81 } | 81 } |
82 | 82 |
83 bool Channel::ChannelImpl::Send(Message* message) { | 83 bool ChannelWin::Send(Message* message) { |
84 DCHECK(thread_check_->CalledOnValidThread()); | 84 DCHECK(thread_check_->CalledOnValidThread()); |
85 DVLOG(2) << "sending message @" << message << " on channel @" << this | 85 DVLOG(2) << "sending message @" << message << " on channel @" << this |
86 << " with type " << message->type() | 86 << " with type " << message->type() |
87 << " (" << output_queue_.size() << " in queue)"; | 87 << " (" << output_queue_.size() << " in queue)"; |
88 | 88 |
89 #ifdef IPC_MESSAGE_LOG_ENABLED | 89 #ifdef IPC_MESSAGE_LOG_ENABLED |
90 Logging::GetInstance()->OnSendMessage(message, ""); | 90 Logging::GetInstance()->OnSendMessage(message, ""); |
91 #endif | 91 #endif |
92 | 92 |
93 message->TraceMessageBegin(); | 93 message->TraceMessageBegin(); |
94 output_queue_.push(message); | 94 output_queue_.push(message); |
95 // ensure waiting to write | 95 // ensure waiting to write |
96 if (!waiting_connect_) { | 96 if (!waiting_connect_) { |
97 if (!output_state_.is_pending) { | 97 if (!output_state_.is_pending) { |
98 if (!ProcessOutgoingMessages(NULL, 0)) | 98 if (!ProcessOutgoingMessages(NULL, 0)) |
99 return false; | 99 return false; |
100 } | 100 } |
101 } | 101 } |
102 | 102 |
103 return true; | 103 return true; |
104 } | 104 } |
105 | 105 |
| 106 base::ProcessId ChannelWin::GetPeerPID() const { |
| 107 return peer_pid_; |
| 108 } |
| 109 |
106 // static | 110 // static |
107 bool Channel::ChannelImpl::IsNamedServerInitialized( | 111 bool ChannelWin::IsNamedServerInitialized( |
108 const std::string& channel_id) { | 112 const std::string& channel_id) { |
109 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1)) | 113 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1)) |
110 return true; | 114 return true; |
111 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another | 115 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another |
112 // connection. | 116 // connection. |
113 return GetLastError() == ERROR_SEM_TIMEOUT; | 117 return GetLastError() == ERROR_SEM_TIMEOUT; |
114 } | 118 } |
115 | 119 |
116 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( | 120 ChannelWin::ReadState ChannelWin::ReadData( |
117 char* buffer, | 121 char* buffer, |
118 int buffer_len, | 122 int buffer_len, |
119 int* /* bytes_read */) { | 123 int* /* bytes_read */) { |
120 if (INVALID_HANDLE_VALUE == pipe_) | 124 if (INVALID_HANDLE_VALUE == pipe_) |
121 return READ_FAILED; | 125 return READ_FAILED; |
122 | 126 |
123 DWORD bytes_read = 0; | 127 DWORD bytes_read = 0; |
124 BOOL ok = ReadFile(pipe_, buffer, buffer_len, | 128 BOOL ok = ReadFile(pipe_, buffer, buffer_len, |
125 &bytes_read, &input_state_.context.overlapped); | 129 &bytes_read, &input_state_.context.overlapped); |
126 if (!ok) { | 130 if (!ok) { |
(...skipping 11 matching lines...) Expand all Loading... |
138 // will be signalled even in the "synchronously completed" state. | 142 // will be signalled even in the "synchronously completed" state. |
139 // | 143 // |
140 // This allows us to potentially process some outgoing messages and | 144 // This allows us to potentially process some outgoing messages and |
141 // interleave other work on this thread when we're getting hammered with | 145 // interleave other work on this thread when we're getting hammered with |
142 // input messages. Potentially, this could be tuned to be more efficient | 146 // input messages. Potentially, this could be tuned to be more efficient |
143 // with some testing. | 147 // with some testing. |
144 input_state_.is_pending = true; | 148 input_state_.is_pending = true; |
145 return READ_PENDING; | 149 return READ_PENDING; |
146 } | 150 } |
147 | 151 |
148 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { | 152 bool ChannelWin::WillDispatchInputMessage(Message* msg) { |
149 // Make sure we get a hello when client validation is required. | 153 // Make sure we get a hello when client validation is required. |
150 if (validate_client_) | 154 if (validate_client_) |
151 return IsHelloMessage(*msg); | 155 return IsHelloMessage(*msg); |
152 return true; | 156 return true; |
153 } | 157 } |
154 | 158 |
155 void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { | 159 void ChannelWin::HandleInternalMessage(const Message& msg) { |
156 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE)); | 160 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE)); |
157 // The hello message contains one parameter containing the PID. | 161 // The hello message contains one parameter containing the PID. |
158 PickleIterator it(msg); | 162 PickleIterator it(msg); |
159 int32 claimed_pid; | 163 int32 claimed_pid; |
160 bool failed = !it.ReadInt(&claimed_pid); | 164 bool failed = !it.ReadInt(&claimed_pid); |
161 | 165 |
162 if (!failed && validate_client_) { | 166 if (!failed && validate_client_) { |
163 int32 secret; | 167 int32 secret; |
164 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true; | 168 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true; |
165 } | 169 } |
166 | 170 |
167 if (failed) { | 171 if (failed) { |
168 NOTREACHED(); | 172 NOTREACHED(); |
169 Close(); | 173 Close(); |
170 listener()->OnChannelError(); | 174 listener()->OnChannelError(); |
171 return; | 175 return; |
172 } | 176 } |
173 | 177 |
174 peer_pid_ = claimed_pid; | 178 peer_pid_ = claimed_pid; |
175 // Validation completed. | 179 // Validation completed. |
176 validate_client_ = false; | 180 validate_client_ = false; |
177 listener()->OnChannelConnected(claimed_pid); | 181 listener()->OnChannelConnected(claimed_pid); |
178 } | 182 } |
179 | 183 |
180 bool Channel::ChannelImpl::DidEmptyInputBuffers() { | 184 bool ChannelWin::DidEmptyInputBuffers() { |
181 // We don't need to do anything here. | 185 // We don't need to do anything here. |
182 return true; | 186 return true; |
183 } | 187 } |
184 | 188 |
185 // static | 189 // static |
186 const base::string16 Channel::ChannelImpl::PipeName( | 190 const base::string16 ChannelWin::PipeName( |
187 const std::string& channel_id, int32* secret) { | 191 const std::string& channel_id, int32* secret) { |
188 std::string name("\\\\.\\pipe\\chrome."); | 192 std::string name("\\\\.\\pipe\\chrome."); |
189 | 193 |
190 // Prevent the shared secret from ending up in the pipe name. | 194 // Prevent the shared secret from ending up in the pipe name. |
191 size_t index = channel_id.find_first_of('\\'); | 195 size_t index = channel_id.find_first_of('\\'); |
192 if (index != std::string::npos) { | 196 if (index != std::string::npos) { |
193 if (secret) // Retrieve the secret if asked for. | 197 if (secret) // Retrieve the secret if asked for. |
194 base::StringToInt(channel_id.substr(index + 1), secret); | 198 base::StringToInt(channel_id.substr(index + 1), secret); |
195 return base::ASCIIToWide(name.append(channel_id.substr(0, index - 1))); | 199 return base::ASCIIToWide(name.append(channel_id.substr(0, index - 1))); |
196 } | 200 } |
197 | 201 |
198 // This case is here to support predictable named pipes in tests. | 202 // This case is here to support predictable named pipes in tests. |
199 if (secret) | 203 if (secret) |
200 *secret = 0; | 204 *secret = 0; |
201 return base::ASCIIToWide(name.append(channel_id)); | 205 return base::ASCIIToWide(name.append(channel_id)); |
202 } | 206 } |
203 | 207 |
204 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, | 208 bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle, |
205 Mode mode) { | 209 Mode mode) { |
206 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); | 210 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); |
207 base::string16 pipe_name; | 211 base::string16 pipe_name; |
208 // If we already have a valid pipe for channel just copy it. | 212 // If we already have a valid pipe for channel just copy it. |
209 if (channel_handle.pipe.handle) { | 213 if (channel_handle.pipe.handle) { |
210 DCHECK(channel_handle.name.empty()); | 214 DCHECK(channel_handle.name.empty()); |
211 pipe_name = L"Not Available"; // Just used for LOG | 215 pipe_name = L"Not Available"; // Just used for LOG |
212 // Check that the given pipe confirms to the specified mode. We can | 216 // Check that the given pipe confirms to the specified mode. We can |
213 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the | 217 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the |
214 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0. | 218 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 (secret && !m->WriteUInt32(secret))) { | 283 (secret && !m->WriteUInt32(secret))) { |
280 CloseHandle(pipe_); | 284 CloseHandle(pipe_); |
281 pipe_ = INVALID_HANDLE_VALUE; | 285 pipe_ = INVALID_HANDLE_VALUE; |
282 return false; | 286 return false; |
283 } | 287 } |
284 | 288 |
285 output_queue_.push(m.release()); | 289 output_queue_.push(m.release()); |
286 return true; | 290 return true; |
287 } | 291 } |
288 | 292 |
289 bool Channel::ChannelImpl::Connect() { | 293 bool ChannelWin::Connect() { |
290 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once"; | 294 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once"; |
291 | 295 |
292 if (!thread_check_.get()) | 296 if (!thread_check_.get()) |
293 thread_check_.reset(new base::ThreadChecker()); | 297 thread_check_.reset(new base::ThreadChecker()); |
294 | 298 |
295 if (pipe_ == INVALID_HANDLE_VALUE) | 299 if (pipe_ == INVALID_HANDLE_VALUE) |
296 return false; | 300 return false; |
297 | 301 |
298 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_, this); | 302 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_, this); |
299 | 303 |
300 // Check to see if there is a client connected to our pipe... | 304 // Check to see if there is a client connected to our pipe... |
301 if (waiting_connect_) | 305 if (waiting_connect_) |
302 ProcessConnection(); | 306 ProcessConnection(); |
303 | 307 |
304 if (!input_state_.is_pending) { | 308 if (!input_state_.is_pending) { |
305 // Complete setup asynchronously. By not setting input_state_.is_pending | 309 // Complete setup asynchronously. By not setting input_state_.is_pending |
306 // to true, we indicate to OnIOCompleted that this is the special | 310 // to true, we indicate to OnIOCompleted that this is the special |
307 // initialization signal. | 311 // initialization signal. |
308 base::MessageLoopForIO::current()->PostTask( | 312 base::MessageLoopForIO::current()->PostTask( |
309 FROM_HERE, | 313 FROM_HERE, |
310 base::Bind(&Channel::ChannelImpl::OnIOCompleted, | 314 base::Bind(&ChannelWin::OnIOCompleted, |
311 weak_factory_.GetWeakPtr(), | 315 weak_factory_.GetWeakPtr(), |
312 &input_state_.context, | 316 &input_state_.context, |
313 0, | 317 0, |
314 0)); | 318 0)); |
315 } | 319 } |
316 | 320 |
317 if (!waiting_connect_) | 321 if (!waiting_connect_) |
318 ProcessOutgoingMessages(NULL, 0); | 322 ProcessOutgoingMessages(NULL, 0); |
319 return true; | 323 return true; |
320 } | 324 } |
321 | 325 |
322 bool Channel::ChannelImpl::ProcessConnection() { | 326 bool ChannelWin::ProcessConnection() { |
323 DCHECK(thread_check_->CalledOnValidThread()); | 327 DCHECK(thread_check_->CalledOnValidThread()); |
324 if (input_state_.is_pending) | 328 if (input_state_.is_pending) |
325 input_state_.is_pending = false; | 329 input_state_.is_pending = false; |
326 | 330 |
327 // Do we have a client connected to our pipe? | 331 // Do we have a client connected to our pipe? |
328 if (INVALID_HANDLE_VALUE == pipe_) | 332 if (INVALID_HANDLE_VALUE == pipe_) |
329 return false; | 333 return false; |
330 | 334 |
331 BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped); | 335 BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped); |
332 | 336 |
(...skipping 16 matching lines...) Expand all Loading... |
349 // The pipe is being closed. | 353 // The pipe is being closed. |
350 return false; | 354 return false; |
351 default: | 355 default: |
352 NOTREACHED(); | 356 NOTREACHED(); |
353 return false; | 357 return false; |
354 } | 358 } |
355 | 359 |
356 return true; | 360 return true; |
357 } | 361 } |
358 | 362 |
359 bool Channel::ChannelImpl::ProcessOutgoingMessages( | 363 bool ChannelWin::ProcessOutgoingMessages( |
360 base::MessageLoopForIO::IOContext* context, | 364 base::MessageLoopForIO::IOContext* context, |
361 DWORD bytes_written) { | 365 DWORD bytes_written) { |
362 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 366 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
363 // no connection? | 367 // no connection? |
364 DCHECK(thread_check_->CalledOnValidThread()); | 368 DCHECK(thread_check_->CalledOnValidThread()); |
365 | 369 |
366 if (output_state_.is_pending) { | 370 if (output_state_.is_pending) { |
367 DCHECK(context); | 371 DCHECK(context); |
368 output_state_.is_pending = false; | 372 output_state_.is_pending = false; |
369 if (!context || bytes_written == 0) { | 373 if (!context || bytes_written == 0) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 return false; | 410 return false; |
407 } | 411 } |
408 | 412 |
409 DVLOG(2) << "sent message @" << m << " on channel @" << this | 413 DVLOG(2) << "sent message @" << m << " on channel @" << this |
410 << " with type " << m->type(); | 414 << " with type " << m->type(); |
411 | 415 |
412 output_state_.is_pending = true; | 416 output_state_.is_pending = true; |
413 return true; | 417 return true; |
414 } | 418 } |
415 | 419 |
416 void Channel::ChannelImpl::OnIOCompleted( | 420 void ChannelWin::OnIOCompleted( |
417 base::MessageLoopForIO::IOContext* context, | 421 base::MessageLoopForIO::IOContext* context, |
418 DWORD bytes_transfered, | 422 DWORD bytes_transfered, |
419 DWORD error) { | 423 DWORD error) { |
420 bool ok = true; | 424 bool ok = true; |
421 DCHECK(thread_check_->CalledOnValidThread()); | 425 DCHECK(thread_check_->CalledOnValidThread()); |
422 if (context == &input_state_.context) { | 426 if (context == &input_state_.context) { |
423 if (waiting_connect_) { | 427 if (waiting_connect_) { |
424 if (!ProcessConnection()) | 428 if (!ProcessConnection()) |
425 return; | 429 return; |
426 // We may have some messages queued up to send... | 430 // We may have some messages queued up to send... |
(...skipping 29 matching lines...) Expand all Loading... |
456 ok = ProcessOutgoingMessages(context, bytes_transfered); | 460 ok = ProcessOutgoingMessages(context, bytes_transfered); |
457 } | 461 } |
458 if (!ok && INVALID_HANDLE_VALUE != pipe_) { | 462 if (!ok && INVALID_HANDLE_VALUE != pipe_) { |
459 // We don't want to re-enter Close(). | 463 // We don't want to re-enter Close(). |
460 Close(); | 464 Close(); |
461 listener()->OnChannelError(); | 465 listener()->OnChannelError(); |
462 } | 466 } |
463 } | 467 } |
464 | 468 |
465 //------------------------------------------------------------------------------ | 469 //------------------------------------------------------------------------------ |
466 // Channel's methods simply call through to ChannelImpl. | 470 // Channel's methods |
467 Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, | |
468 Listener* listener) | |
469 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { | |
470 } | |
471 | 471 |
472 Channel::~Channel() { | 472 // static |
473 delete channel_impl_; | 473 scoped_ptr<Channel> Channel::Create( |
474 } | 474 const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) { |
475 | 475 return scoped_ptr<Channel>( |
476 bool Channel::Connect() { | 476 new ChannelWin(channel_handle, mode, listener)); |
477 return channel_impl_->Connect(); | |
478 } | |
479 | |
480 void Channel::Close() { | |
481 if (channel_impl_) | |
482 channel_impl_->Close(); | |
483 } | |
484 | |
485 base::ProcessId Channel::peer_pid() const { | |
486 return channel_impl_->peer_pid(); | |
487 } | |
488 | |
489 bool Channel::Send(Message* message) { | |
490 return channel_impl_->Send(message); | |
491 } | 477 } |
492 | 478 |
493 // static | 479 // static |
494 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { | 480 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { |
495 return ChannelImpl::IsNamedServerInitialized(channel_id); | 481 return ChannelWin::IsNamedServerInitialized(channel_id); |
496 } | 482 } |
497 | 483 |
498 // static | 484 // static |
499 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { | 485 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { |
500 // Windows pipes can be enumerated by low-privileged processes. So, we | 486 // Windows pipes can be enumerated by low-privileged processes. So, we |
501 // append a strong random value after the \ character. This value is not | 487 // append a strong random value after the \ character. This value is not |
502 // included in the pipe name, but sent as part of the client hello, to | 488 // included in the pipe name, but sent as part of the client hello, to |
503 // hijacking the pipe name to spoof the client. | 489 // hijacking the pipe name to spoof the client. |
504 | 490 |
505 std::string id = prefix; | 491 std::string id = prefix; |
506 if (!id.empty()) | 492 if (!id.empty()) |
507 id.append("."); | 493 id.append("."); |
508 | 494 |
509 int secret; | 495 int secret; |
510 do { // Guarantee we get a non-zero value. | 496 do { // Guarantee we get a non-zero value. |
511 secret = base::RandInt(0, std::numeric_limits<int>::max()); | 497 secret = base::RandInt(0, std::numeric_limits<int>::max()); |
512 } while (secret == 0); | 498 } while (secret == 0); |
513 | 499 |
514 id.append(GenerateUniqueRandomChannelID()); | 500 id.append(GenerateUniqueRandomChannelID()); |
515 return id.append(base::StringPrintf("\\%d", secret)); | 501 return id.append(base::StringPrintf("\\%d", secret)); |
516 } | 502 } |
517 | 503 |
518 } // namespace IPC | 504 } // namespace IPC |
OLD | NEW |