| 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 |