blob: 9182200d440b7f13bed7fc0c874e3b1bbeb7ce9e [file] [log] [blame]
[email protected]b90d7e802011-01-09 16:32:201// Copyright (c) 2011 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>
[email protected]935aa542010-10-15 01:59:158#include <sddl.h>
initial.commit09911bf2008-07-26 23:55:299#include <sstream>
10
[email protected]5be7da242009-11-20 23:16:2611#include "base/auto_reset.h"
[email protected]c1afbd2c2008-10-13 19:19:3612#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/logging.h"
[email protected]c9177502011-01-01 04:48:4914#include "base/threading/non_thread_safe.h"
[email protected]be1ce6a72010-08-03 14:35:2215#include "base/utf_string_conversions.h"
[email protected]b90d7e802011-01-09 16:32:2016#include "base/win/scoped_handle.h"
[email protected]946d1b22009-07-22 23:57:2117#include "ipc/ipc_logging.h"
18#include "ipc/ipc_message_utils.h"
initial.commit09911bf2008-07-26 23:55:2919
initial.commit09911bf2008-07-26 23:55:2920namespace IPC {
[email protected]935aa542010-10-15 01:59:1521
22namespace {
23
24// Creates a security descriptor with a DACL that has one ace giving full
25// access to the current logon session.
26// The security descriptor returned must be freed using LocalFree.
27// The function returns true if it succeeds, false otherwise.
28bool GetLogonSessionOnlyDACL(SECURITY_DESCRIPTOR** security_descriptor) {
29 // Get the current token.
30 HANDLE token = NULL;
31 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
32 return false;
[email protected]b90d7e802011-01-09 16:32:2033 base::win::ScopedHandle token_scoped(token);
[email protected]935aa542010-10-15 01:59:1534
35 // Get the size of the TokenGroups structure.
36 DWORD size = 0;
37 BOOL result = GetTokenInformation(token, TokenGroups, NULL, 0, &size);
38 if (result != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
39 return false;
40
41 // Get the data.
42 scoped_array<char> token_groups_chars(new char[size]);
43 TOKEN_GROUPS* token_groups =
44 reinterpret_cast<TOKEN_GROUPS*>(token_groups_chars.get());
45
46 if (!GetTokenInformation(token, TokenGroups, token_groups, size, &size))
47 return false;
48
49 // Look for the logon sid.
50 SID* logon_sid = NULL;
51 for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
52 if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
53 logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
54 break;
55 }
56 }
57
58 if (!logon_sid)
59 return false;
60
61 // Convert the data to a string.
62 wchar_t* sid_string;
63 if (!ConvertSidToStringSid(logon_sid, &sid_string))
64 return false;
65
66 static const wchar_t dacl_format[] = L"D:(A;OICI;GA;;;%ls)";
67 wchar_t dacl[SECURITY_MAX_SID_SIZE + arraysize(dacl_format) + 1] = {0};
68 wsprintf(dacl, dacl_format, sid_string);
69
70 LocalFree(sid_string);
71
72 // Convert the string to a security descriptor
73 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
74 dacl,
75 SDDL_REVISION_1,
76 reinterpret_cast<PSECURITY_DESCRIPTOR*>(security_descriptor),
77 NULL)) {
78 return false;
79 }
80
81 return true;
82}
83
84} // namespace
85
initial.commit09911bf2008-07-26 23:55:2986//------------------------------------------------------------------------------
87
[email protected]514411fc2008-12-10 22:28:1188Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) {
[email protected]17b89142008-11-07 21:52:1589 memset(&context.overlapped, 0, sizeof(context.overlapped));
90 context.handler = channel;
initial.commit09911bf2008-07-26 23:55:2991}
92
[email protected]514411fc2008-12-10 22:28:1193Channel::ChannelImpl::State::~State() {
94 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context),
95 starts_with_io_context);
initial.commit09911bf2008-07-26 23:55:2996}
97
98//------------------------------------------------------------------------------
99
[email protected]42ce94e2010-12-08 19:28:09100Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle,
101 Mode mode, Listener* listener)
[email protected]17b89142008-11-07 21:52:15102 : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
103 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
104 pipe_(INVALID_HANDLE_VALUE),
initial.commit09911bf2008-07-26 23:55:29105 listener_(listener),
[email protected]1707726c2011-02-03 20:35:09106 waiting_connect_(mode & MODE_SERVER_FLAG),
[email protected]c1afbd2c2008-10-13 19:19:36107 processing_incoming_(false),
108 ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
[email protected]42ce94e2010-12-08 19:28:09109 if (!CreatePipe(channel_handle, mode)) {
initial.commit09911bf2008-07-26 23:55:29110 // The pipe may have been closed already.
[email protected]42ce94e2010-12-08 19:28:09111 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name <<
initial.commit09911bf2008-07-26 23:55:29112 "\" in " << (mode == 0 ? "server" : "client") << " mode.";
113 }
114}
115
[email protected]601858c02010-09-01 17:08:20116Channel::ChannelImpl::~ChannelImpl() {
117 Close();
118}
119
[email protected]514411fc2008-12-10 22:28:11120void Channel::ChannelImpl::Close() {
[email protected]c1e4bff32009-01-29 00:07:06121 if (thread_check_.get()) {
122 DCHECK(thread_check_->CalledOnValidThread());
123 }
124
[email protected]74f87acf22009-10-14 22:10:40125 if (input_state_.is_pending || output_state_.is_pending)
[email protected]17b89142008-11-07 21:52:15126 CancelIo(pipe_);
[email protected]ee78622d2008-10-13 21:25:50127
[email protected]17b89142008-11-07 21:52:15128 // Closing the handle at this point prevents us from issuing more requests
129 // form OnIOCompleted().
initial.commit09911bf2008-07-26 23:55:29130 if (pipe_ != INVALID_HANDLE_VALUE) {
131 CloseHandle(pipe_);
132 pipe_ = INVALID_HANDLE_VALUE;
133 }
134
[email protected]17b89142008-11-07 21:52:15135 // Make sure all IO has completed.
136 base::Time start = base::Time::Now();
137 while (input_state_.is_pending || output_state_.is_pending) {
138 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
139 }
[email protected]17b89142008-11-07 21:52:15140
initial.commit09911bf2008-07-26 23:55:29141 while (!output_queue_.empty()) {
142 Message* m = output_queue_.front();
143 output_queue_.pop();
144 delete m;
145 }
146}
147
[email protected]514411fc2008-12-10 22:28:11148bool Channel::ChannelImpl::Send(Message* message) {
[email protected]c1e4bff32009-01-29 00:07:06149 DCHECK(thread_check_->CalledOnValidThread());
[email protected]2a9d601b2010-10-19 23:50:00150 DVLOG(2) << "sending message @" << message << " on channel @" << this
151 << " with type " << message->type()
152 << " (" << output_queue_.size() << " in queue)";
initial.commit09911bf2008-07-26 23:55:29153
154#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]8e8bb6d2010-12-13 08:18:55155 Logging::GetInstance()->OnSendMessage(message, "");
initial.commit09911bf2008-07-26 23:55:29156#endif
157
158 output_queue_.push(message);
159 // ensure waiting to write
160 if (!waiting_connect_) {
161 if (!output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36162 if (!ProcessOutgoingMessages(NULL, 0))
initial.commit09911bf2008-07-26 23:55:29163 return false;
initial.commit09911bf2008-07-26 23:55:29164 }
165 }
166
167 return true;
168}
169
[email protected]d3216442009-03-05 21:07:27170const std::wstring Channel::ChannelImpl::PipeName(
[email protected]9a3a293b2009-06-04 22:28:16171 const std::string& channel_id) const {
[email protected]514411fc2008-12-10 22:28:11172 std::wostringstream ss;
initial.commit09911bf2008-07-26 23:55:29173 // XXX(darin): get application name from somewhere else
[email protected]9a3a293b2009-06-04 22:28:16174 ss << L"\\\\.\\pipe\\chrome." << ASCIIToWide(channel_id);
initial.commit09911bf2008-07-26 23:55:29175 return ss.str();
176}
177
[email protected]42ce94e2010-12-08 19:28:09178bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
[email protected]514411fc2008-12-10 22:28:11179 Mode mode) {
initial.commit09911bf2008-07-26 23:55:29180 DCHECK(pipe_ == INVALID_HANDLE_VALUE);
[email protected]42ce94e2010-12-08 19:28:09181 const std::wstring pipe_name = PipeName(channel_handle.name);
[email protected]1707726c2011-02-03 20:35:09182 if (mode & MODE_SERVER_FLAG) {
initial.commit09911bf2008-07-26 23:55:29183 SECURITY_ATTRIBUTES security_attributes = {0};
184 security_attributes.bInheritHandle = FALSE;
185 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
[email protected]935aa542010-10-15 01:59:15186 if (!GetLogonSessionOnlyDACL(
initial.commit09911bf2008-07-26 23:55:29187 reinterpret_cast<SECURITY_DESCRIPTOR**>(
188 &security_attributes.lpSecurityDescriptor))) {
189 NOTREACHED();
190 }
191
192 pipe_ = CreateNamedPipeW(pipe_name.c_str(),
193 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
194 FILE_FLAG_FIRST_PIPE_INSTANCE,
195 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
196 1, // number of pipe instances
[email protected]514411fc2008-12-10 22:28:11197 // output buffer size (XXX tune)
198 Channel::kReadBufferSize,
199 // input buffer size (XXX tune)
200 Channel::kReadBufferSize,
initial.commit09911bf2008-07-26 23:55:29201 5000, // timeout in milliseconds (XXX tune)
202 &security_attributes);
203 LocalFree(security_attributes.lpSecurityDescriptor);
[email protected]1707726c2011-02-03 20:35:09204 } else if (mode & MODE_CLIENT_FLAG) {
initial.commit09911bf2008-07-26 23:55:29205 pipe_ = CreateFileW(pipe_name.c_str(),
206 GENERIC_READ | GENERIC_WRITE,
207 0,
208 NULL,
209 OPEN_EXISTING,
210 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
211 FILE_FLAG_OVERLAPPED,
212 NULL);
[email protected]1707726c2011-02-03 20:35:09213 } else {
214 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29215 }
216 if (pipe_ == INVALID_HANDLE_VALUE) {
217 // If this process is being closed, the pipe may be gone already.
218 LOG(WARNING) << "failed to create pipe: " << GetLastError();
219 return false;
220 }
221
222 // Create the Hello message to be sent when Connect is called
223 scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
224 HELLO_MESSAGE_TYPE,
225 IPC::Message::PRIORITY_NORMAL));
226 if (!m->WriteInt(GetCurrentProcessId())) {
227 CloseHandle(pipe_);
228 pipe_ = INVALID_HANDLE_VALUE;
229 return false;
230 }
231
232 output_queue_.push(m.release());
233 return true;
234}
235
[email protected]514411fc2008-12-10 22:28:11236bool Channel::ChannelImpl::Connect() {
[email protected]19340722009-08-17 19:53:25237 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
initial.commit09911bf2008-07-26 23:55:29238
[email protected]c1e4bff32009-01-29 00:07:06239 if (!thread_check_.get())
[email protected]c9177502011-01-01 04:48:49240 thread_check_.reset(new base::NonThreadSafe());
[email protected]c1e4bff32009-01-29 00:07:06241
initial.commit09911bf2008-07-26 23:55:29242 if (pipe_ == INVALID_HANDLE_VALUE)
243 return false;
244
[email protected]c1afbd2c2008-10-13 19:19:36245 MessageLoopForIO::current()->RegisterIOHandler(pipe_, this);
246
initial.commit09911bf2008-07-26 23:55:29247 // Check to see if there is a client connected to our pipe...
248 if (waiting_connect_)
249 ProcessConnection();
250
251 if (!input_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36252 // Complete setup asynchronously. By not setting input_state_.is_pending
253 // to true, we indicate to OnIOCompleted that this is the special
254 // initialization signal.
255 MessageLoopForIO::current()->PostTask(FROM_HERE, factory_.NewRunnableMethod(
[email protected]514411fc2008-12-10 22:28:11256 &Channel::ChannelImpl::OnIOCompleted, &input_state_.context, 0, 0));
initial.commit09911bf2008-07-26 23:55:29257 }
258
259 if (!waiting_connect_)
[email protected]c1afbd2c2008-10-13 19:19:36260 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29261 return true;
262}
263
[email protected]514411fc2008-12-10 22:28:11264bool Channel::ChannelImpl::ProcessConnection() {
[email protected]c1e4bff32009-01-29 00:07:06265 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15266 if (input_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36267 input_state_.is_pending = false;
initial.commit09911bf2008-07-26 23:55:29268
269 // Do we have a client connected to our pipe?
[email protected]17b89142008-11-07 21:52:15270 if (INVALID_HANDLE_VALUE == pipe_)
271 return false;
272
273 BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped);
initial.commit09911bf2008-07-26 23:55:29274
275 DWORD err = GetLastError();
276 if (ok) {
277 // Uhm, the API documentation says that this function should never
278 // return success when used in overlapped mode.
279 NOTREACHED();
280 return false;
281 }
282
283 switch (err) {
284 case ERROR_IO_PENDING:
285 input_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29286 break;
287 case ERROR_PIPE_CONNECTED:
288 waiting_connect_ = false;
289 break;
[email protected]20aa32c2009-07-14 22:25:49290 case ERROR_NO_DATA:
291 // The pipe is being closed.
292 return false;
initial.commit09911bf2008-07-26 23:55:29293 default:
294 NOTREACHED();
295 return false;
296 }
297
298 return true;
299}
300
[email protected]514411fc2008-12-10 22:28:11301bool Channel::ChannelImpl::ProcessIncomingMessages(
302 MessageLoopForIO::IOContext* context,
303 DWORD bytes_read) {
[email protected]c1e4bff32009-01-29 00:07:06304 DCHECK(thread_check_->CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29305 if (input_state_.is_pending) {
306 input_state_.is_pending = false;
[email protected]c1afbd2c2008-10-13 19:19:36307 DCHECK(context);
initial.commit09911bf2008-07-26 23:55:29308
[email protected]c1afbd2c2008-10-13 19:19:36309 if (!context || !bytes_read)
initial.commit09911bf2008-07-26 23:55:29310 return false;
initial.commit09911bf2008-07-26 23:55:29311 } else {
[email protected]c1afbd2c2008-10-13 19:19:36312 // This happens at channel initialization.
[email protected]17b89142008-11-07 21:52:15313 DCHECK(!bytes_read && context == &input_state_.context);
initial.commit09911bf2008-07-26 23:55:29314 }
315
316 for (;;) {
317 if (bytes_read == 0) {
[email protected]17b89142008-11-07 21:52:15318 if (INVALID_HANDLE_VALUE == pipe_)
319 return false;
320
[email protected]c1afbd2c2008-10-13 19:19:36321 // Read from pipe...
initial.commit09911bf2008-07-26 23:55:29322 BOOL ok = ReadFile(pipe_,
323 input_buf_,
[email protected]514411fc2008-12-10 22:28:11324 Channel::kReadBufferSize,
initial.commit09911bf2008-07-26 23:55:29325 &bytes_read,
[email protected]17b89142008-11-07 21:52:15326 &input_state_.context.overlapped);
initial.commit09911bf2008-07-26 23:55:29327 if (!ok) {
328 DWORD err = GetLastError();
329 if (err == ERROR_IO_PENDING) {
initial.commit09911bf2008-07-26 23:55:29330 input_state_.is_pending = true;
331 return true;
332 }
333 LOG(ERROR) << "pipe error: " << err;
334 return false;
335 }
[email protected]17b89142008-11-07 21:52:15336 input_state_.is_pending = true;
337 return true;
initial.commit09911bf2008-07-26 23:55:29338 }
339 DCHECK(bytes_read);
340
[email protected]c1afbd2c2008-10-13 19:19:36341 // Process messages from input buffer.
initial.commit09911bf2008-07-26 23:55:29342
343 const char* p, *end;
344 if (input_overflow_buf_.empty()) {
345 p = input_buf_;
346 end = p + bytes_read;
347 } else {
348 if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) {
349 input_overflow_buf_.clear();
350 LOG(ERROR) << "IPC message is too big";
351 return false;
352 }
353 input_overflow_buf_.append(input_buf_, bytes_read);
354 p = input_overflow_buf_.data();
355 end = p + input_overflow_buf_.size();
356 }
357
358 while (p < end) {
359 const char* message_tail = Message::FindNext(p, end);
360 if (message_tail) {
361 int len = static_cast<int>(message_tail - p);
362 const Message m(p, len);
[email protected]2a9d601b2010-10-19 23:50:00363 DVLOG(2) << "received message on channel @" << this
364 << " with type " << m.type();
initial.commit09911bf2008-07-26 23:55:29365 if (m.routing_id() == MSG_ROUTING_NONE &&
366 m.type() == HELLO_MESSAGE_TYPE) {
367 // The Hello message contains only the process id.
368 listener_->OnChannelConnected(MessageIterator(m).NextInt());
369 } else {
370 listener_->OnMessageReceived(m);
371 }
372 p = message_tail;
373 } else {
[email protected]c1afbd2c2008-10-13 19:19:36374 // Last message is partial.
initial.commit09911bf2008-07-26 23:55:29375 break;
376 }
377 }
378 input_overflow_buf_.assign(p, end - p);
379
[email protected]c1afbd2c2008-10-13 19:19:36380 bytes_read = 0; // Get more data.
initial.commit09911bf2008-07-26 23:55:29381 }
382
383 return true;
384}
385
[email protected]514411fc2008-12-10 22:28:11386bool Channel::ChannelImpl::ProcessOutgoingMessages(
387 MessageLoopForIO::IOContext* context,
388 DWORD bytes_written) {
initial.commit09911bf2008-07-26 23:55:29389 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
390 // no connection?
[email protected]c1e4bff32009-01-29 00:07:06391 DCHECK(thread_check_->CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29392
393 if (output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36394 DCHECK(context);
initial.commit09911bf2008-07-26 23:55:29395 output_state_.is_pending = false;
[email protected]c1afbd2c2008-10-13 19:19:36396 if (!context || bytes_written == 0) {
initial.commit09911bf2008-07-26 23:55:29397 DWORD err = GetLastError();
398 LOG(ERROR) << "pipe error: " << err;
399 return false;
400 }
[email protected]c1afbd2c2008-10-13 19:19:36401 // Message was sent.
initial.commit09911bf2008-07-26 23:55:29402 DCHECK(!output_queue_.empty());
403 Message* m = output_queue_.front();
404 output_queue_.pop();
405 delete m;
406 }
407
[email protected]17b89142008-11-07 21:52:15408 if (output_queue_.empty())
409 return true;
410
411 if (INVALID_HANDLE_VALUE == pipe_)
412 return false;
413
414 // Write to pipe...
415 Message* m = output_queue_.front();
[email protected]8a861402011-01-28 19:59:11416 DCHECK(m->size() <= INT_MAX);
[email protected]17b89142008-11-07 21:52:15417 BOOL ok = WriteFile(pipe_,
418 m->data(),
[email protected]8a861402011-01-28 19:59:11419 static_cast<int>(m->size()),
[email protected]17b89142008-11-07 21:52:15420 &bytes_written,
421 &output_state_.context.overlapped);
422 if (!ok) {
423 DWORD err = GetLastError();
424 if (err == ERROR_IO_PENDING) {
425 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29426
[email protected]2a9d601b2010-10-19 23:50:00427 DVLOG(2) << "sent pending message @" << m << " on channel @" << this
428 << " with type " << m->type();
initial.commit09911bf2008-07-26 23:55:29429
[email protected]17b89142008-11-07 21:52:15430 return true;
initial.commit09911bf2008-07-26 23:55:29431 }
[email protected]17b89142008-11-07 21:52:15432 LOG(ERROR) << "pipe error: " << err;
433 return false;
initial.commit09911bf2008-07-26 23:55:29434 }
435
[email protected]2a9d601b2010-10-19 23:50:00436 DVLOG(2) << "sent message @" << m << " on channel @" << this
437 << " with type " << m->type();
[email protected]17b89142008-11-07 21:52:15438
439 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29440 return true;
441}
442
[email protected]514411fc2008-12-10 22:28:11443void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context,
[email protected]17b89142008-11-07 21:52:15444 DWORD bytes_transfered, DWORD error) {
initial.commit09911bf2008-07-26 23:55:29445 bool ok;
[email protected]c1e4bff32009-01-29 00:07:06446 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15447 if (context == &input_state_.context) {
initial.commit09911bf2008-07-26 23:55:29448 if (waiting_connect_) {
[email protected]17b89142008-11-07 21:52:15449 if (!ProcessConnection())
450 return;
initial.commit09911bf2008-07-26 23:55:29451 // We may have some messages queued up to send...
452 if (!output_queue_.empty() && !output_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36453 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29454 if (input_state_.is_pending)
455 return;
456 // else, fall-through and look for incoming messages...
457 }
458 // we don't support recursion through OnMessageReceived yet!
459 DCHECK(!processing_incoming_);
[email protected]0fbd70332010-06-01 19:28:34460 AutoReset<bool> auto_reset_processing_incoming(&processing_incoming_, true);
[email protected]c1afbd2c2008-10-13 19:19:36461 ok = ProcessIncomingMessages(context, bytes_transfered);
initial.commit09911bf2008-07-26 23:55:29462 } else {
[email protected]17b89142008-11-07 21:52:15463 DCHECK(context == &output_state_.context);
[email protected]c1afbd2c2008-10-13 19:19:36464 ok = ProcessOutgoingMessages(context, bytes_transfered);
initial.commit09911bf2008-07-26 23:55:29465 }
[email protected]17b89142008-11-07 21:52:15466 if (!ok && INVALID_HANDLE_VALUE != pipe_) {
467 // We don't want to re-enter Close().
initial.commit09911bf2008-07-26 23:55:29468 Close();
469 listener_->OnChannelError();
470 }
471}
472
[email protected]514411fc2008-12-10 22:28:11473//------------------------------------------------------------------------------
474// Channel's methods simply call through to ChannelImpl.
[email protected]42ce94e2010-12-08 19:28:09475Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode,
[email protected]514411fc2008-12-10 22:28:11476 Listener* listener)
[email protected]42ce94e2010-12-08 19:28:09477 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
initial.commit09911bf2008-07-26 23:55:29478}
[email protected]514411fc2008-12-10 22:28:11479
480Channel::~Channel() {
481 delete channel_impl_;
482}
483
484bool Channel::Connect() {
485 return channel_impl_->Connect();
486}
487
488void Channel::Close() {
489 channel_impl_->Close();
490}
491
492void Channel::set_listener(Listener* listener) {
493 channel_impl_->set_listener(listener);
494}
495
496bool Channel::Send(Message* message) {
497 return channel_impl_->Send(message);
498}
499
500} // namespace IPC