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" |
(...skipping 12 matching lines...) Expand all Loading... |
23 context.handler = channel; | 23 context.handler = channel; |
24 } | 24 } |
25 | 25 |
26 Channel::ChannelImpl::State::~State() { | 26 Channel::ChannelImpl::State::~State() { |
27 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), | 27 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), |
28 starts_with_io_context); | 28 starts_with_io_context); |
29 } | 29 } |
30 | 30 |
31 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, | 31 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, |
32 Mode mode, Listener* listener) | 32 Mode mode, Listener* listener) |
33 : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), | 33 : ChannelReader(listener), |
| 34 ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), |
34 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), | 35 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), |
35 pipe_(INVALID_HANDLE_VALUE), | 36 pipe_(INVALID_HANDLE_VALUE), |
36 listener_(listener), | |
37 waiting_connect_(mode & MODE_SERVER_FLAG), | 37 waiting_connect_(mode & MODE_SERVER_FLAG), |
38 processing_incoming_(false), | 38 processing_incoming_(false), |
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
40 CreatePipe(channel_handle, mode); | 40 CreatePipe(channel_handle, mode); |
41 } | 41 } |
42 | 42 |
43 Channel::ChannelImpl::~ChannelImpl() { | 43 Channel::ChannelImpl::~ChannelImpl() { |
44 Close(); | 44 Close(); |
45 } | 45 } |
46 | 46 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 | 106 |
107 | 107 |
108 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( | 108 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( |
109 char* buffer, | 109 char* buffer, |
110 int buffer_len, | 110 int buffer_len, |
111 int* /* bytes_read */) { | 111 int* /* bytes_read */) { |
112 if (INVALID_HANDLE_VALUE == pipe_) | 112 if (INVALID_HANDLE_VALUE == pipe_) |
113 return READ_FAILED; | 113 return READ_FAILED; |
114 | 114 |
115 DWORD bytes_read = 0; | 115 DWORD bytes_read = 0; |
116 BOOL ok = ReadFile(pipe_, input_buf_, Channel::kReadBufferSize, | 116 BOOL ok = ReadFile(pipe_, buffer, buffer_len, |
117 &bytes_read, &input_state_.context.overlapped); | 117 &bytes_read, &input_state_.context.overlapped); |
118 if (!ok) { | 118 if (!ok) { |
119 DWORD err = GetLastError(); | 119 DWORD err = GetLastError(); |
120 if (err == ERROR_IO_PENDING) { | 120 if (err == ERROR_IO_PENDING) { |
121 input_state_.is_pending = true; | 121 input_state_.is_pending = true; |
122 return READ_PENDING; | 122 return READ_PENDING; |
123 } | 123 } |
124 LOG(ERROR) << "pipe error: " << err; | 124 LOG(ERROR) << "pipe error: " << err; |
125 return READ_FAILED; | 125 return READ_FAILED; |
126 } | 126 } |
127 | 127 |
128 // We could return READ_SUCCEEDED here. But the way that this code is | 128 // We could return READ_SUCCEEDED here. But the way that this code is |
129 // structured we instead go back to the message loop. Our completion port | 129 // structured we instead go back to the message loop. Our completion port |
130 // will be signalled even in the "synchronously completed" state. | 130 // will be signalled even in the "synchronously completed" state. |
131 // | 131 // |
132 // This allows us to potentially process some outgoing messages and | 132 // This allows us to potentially process some outgoing messages and |
133 // interleave other work on this thread when we're getting hammered with | 133 // interleave other work on this thread when we're getting hammered with |
134 // input messages. Potentially, this could be tuned to be more efficient | 134 // input messages. Potentially, this could be tuned to be more efficient |
135 // with some testing. | 135 // with some testing. |
136 input_state_.is_pending = true; | 136 input_state_.is_pending = true; |
137 return READ_PENDING; | 137 return READ_PENDING; |
138 } | 138 } |
139 | 139 |
140 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { | 140 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { |
| 141 // We don't need to do anything here. |
141 return true; | 142 return true; |
142 } | 143 } |
143 | 144 |
144 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { | 145 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { |
145 // The hello message contains one parameter containing the PID. | 146 // The hello message contains one parameter containing the PID. |
146 listener_->OnChannelConnected(MessageIterator(msg).NextInt()); | 147 listener()->OnChannelConnected(MessageIterator(msg).NextInt()); |
147 } | 148 } |
148 | 149 |
149 bool Channel::ChannelImpl::DidEmptyInputBuffers() { | 150 bool Channel::ChannelImpl::DidEmptyInputBuffers() { |
| 151 // We don't need to do anything here. |
150 return true; | 152 return true; |
151 } | 153 } |
152 | 154 |
153 bool Channel::ChannelImpl::DispatchInputData(const char* input_data, | |
154 int input_data_len) { | |
155 const char* p; | |
156 const char* end; | |
157 | |
158 // Possibly combine with the overflow buffer to make a larger buffer. | |
159 if (input_overflow_buf_.empty()) { | |
160 p = input_data; | |
161 end = input_data + input_data_len; | |
162 } else { | |
163 if (input_overflow_buf_.size() > | |
164 kMaximumMessageSize - input_data_len) { | |
165 input_overflow_buf_.clear(); | |
166 LOG(ERROR) << "IPC message is too big"; | |
167 return false; | |
168 } | |
169 input_overflow_buf_.append(input_data, input_data_len); | |
170 p = input_overflow_buf_.data(); | |
171 end = p + input_overflow_buf_.size(); | |
172 } | |
173 | |
174 // Dispatch all complete messages in the data buffer. | |
175 while (p < end) { | |
176 const char* message_tail = Message::FindNext(p, end); | |
177 if (message_tail) { | |
178 int len = static_cast<int>(message_tail - p); | |
179 Message m(p, len); | |
180 if (!WillDispatchInputMessage(&m)) | |
181 return false; | |
182 | |
183 if (IsHelloMessage(m)) | |
184 HandleHelloMessage(m); | |
185 else | |
186 listener_->OnMessageReceived(m); | |
187 p = message_tail; | |
188 } else { | |
189 // Last message is partial. | |
190 break; | |
191 } | |
192 } | |
193 | |
194 // Save any partial data in the overflow buffer. | |
195 input_overflow_buf_.assign(p, end - p); | |
196 | |
197 if (input_overflow_buf_.empty() && !DidEmptyInputBuffers()) | |
198 return false; | |
199 return true; | |
200 } | |
201 | |
202 bool Channel::ChannelImpl::IsHelloMessage(const Message& m) const { | |
203 return m.routing_id() == MSG_ROUTING_NONE && m.type() == HELLO_MESSAGE_TYPE; | |
204 } | |
205 | |
206 bool Channel::ChannelImpl::AsyncReadComplete(int bytes_read) { | |
207 return DispatchInputData(input_buf_, bytes_read); | |
208 } | |
209 | |
210 // static | 155 // static |
211 const std::wstring Channel::ChannelImpl::PipeName( | 156 const std::wstring Channel::ChannelImpl::PipeName( |
212 const std::string& channel_id) { | 157 const std::string& channel_id) { |
213 std::string name("\\\\.\\pipe\\chrome."); | 158 std::string name("\\\\.\\pipe\\chrome."); |
214 return ASCIIToWide(name.append(channel_id)); | 159 return ASCIIToWide(name.append(channel_id)); |
215 } | 160 } |
216 | 161 |
217 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, | 162 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, |
218 Mode mode) { | 163 Mode mode) { |
219 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); | 164 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 // The pipe is being closed. | 298 // The pipe is being closed. |
354 return false; | 299 return false; |
355 default: | 300 default: |
356 NOTREACHED(); | 301 NOTREACHED(); |
357 return false; | 302 return false; |
358 } | 303 } |
359 | 304 |
360 return true; | 305 return true; |
361 } | 306 } |
362 | 307 |
363 bool Channel::ChannelImpl::ProcessIncomingMessages() { | |
364 while (true) { | |
365 int bytes_read = 0; | |
366 ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize, | |
367 &bytes_read); | |
368 if (read_state == READ_FAILED) | |
369 return false; | |
370 if (read_state == READ_PENDING) | |
371 return true; | |
372 DCHECK(bytes_read > 0); | |
373 if (!DispatchInputData(input_buf_, bytes_read)) | |
374 return false; | |
375 } | |
376 } | |
377 | |
378 bool Channel::ChannelImpl::ProcessOutgoingMessages( | 308 bool Channel::ChannelImpl::ProcessOutgoingMessages( |
379 MessageLoopForIO::IOContext* context, | 309 MessageLoopForIO::IOContext* context, |
380 DWORD bytes_written) { | 310 DWORD bytes_written) { |
381 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 311 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
382 // no connection? | 312 // no connection? |
383 DCHECK(thread_check_->CalledOnValidThread()); | 313 DCHECK(thread_check_->CalledOnValidThread()); |
384 | 314 |
385 if (output_state_.is_pending) { | 315 if (output_state_.is_pending) { |
386 DCHECK(context); | 316 DCHECK(context); |
387 output_state_.is_pending = false; | 317 output_state_.is_pending = false; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 // Request more data. | 398 // Request more data. |
469 if (ok) | 399 if (ok) |
470 ok = ProcessIncomingMessages(); | 400 ok = ProcessIncomingMessages(); |
471 } else { | 401 } else { |
472 DCHECK(context == &output_state_.context); | 402 DCHECK(context == &output_state_.context); |
473 ok = ProcessOutgoingMessages(context, bytes_transfered); | 403 ok = ProcessOutgoingMessages(context, bytes_transfered); |
474 } | 404 } |
475 if (!ok && INVALID_HANDLE_VALUE != pipe_) { | 405 if (!ok && INVALID_HANDLE_VALUE != pipe_) { |
476 // We don't want to re-enter Close(). | 406 // We don't want to re-enter Close(). |
477 Close(); | 407 Close(); |
478 listener_->OnChannelError(); | 408 listener()->OnChannelError(); |
479 } | 409 } |
480 } | 410 } |
481 | 411 |
482 //------------------------------------------------------------------------------ | 412 //------------------------------------------------------------------------------ |
483 // Channel's methods simply call through to ChannelImpl. | 413 // Channel's methods simply call through to ChannelImpl. |
484 Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, | 414 Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, |
485 Listener* listener) | 415 Listener* listener) |
486 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { | 416 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { |
487 } | 417 } |
488 | 418 |
(...skipping 16 matching lines...) Expand all Loading... |
505 bool Channel::Send(Message* message) { | 435 bool Channel::Send(Message* message) { |
506 return channel_impl_->Send(message); | 436 return channel_impl_->Send(message); |
507 } | 437 } |
508 | 438 |
509 // static | 439 // static |
510 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { | 440 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { |
511 return ChannelImpl::IsNamedServerInitialized(channel_id); | 441 return ChannelImpl::IsNamedServerInitialized(channel_id); |
512 } | 442 } |
513 | 443 |
514 } // namespace IPC | 444 } // namespace IPC |
OLD | NEW |