Index: chrome/browser/extensions/api/messaging/native_message_process_host_win.cc |
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_win.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_win.cc |
index a9a6819f67ba595aaadfcb8c101f7814d29761f3..e89ccc1624426d82882af664c3dd8722e7973f95 100644 |
--- a/chrome/browser/extensions/api/messaging/native_message_process_host_win.cc |
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host_win.cc |
@@ -12,31 +12,138 @@ |
#include "base/process_util.h" |
#include "content/public/browser/browser_thread.h" |
+namespace { |
+ |
+void AddToOverlappedOffset(OVERLAPPED* overlapped, uint32 to_add) { |
+ uint64 full_offset = |
+ static_cast<uint64>(overlapped->OffsetHigh) << 32 | overlapped->Offset; |
+ full_offset += to_add; |
+ overlapped->Offset = full_offset & 0x00000000ffffffff; |
+ overlapped->OffsetHigh = full_offset >> 32; |
+} |
+ |
+} // namespace |
+ |
namespace extensions { |
+void NativeMessageProcessHost::ReadNowForTesting() { |
+} |
+ |
void NativeMessageProcessHost::OnIOCompleted( |
MessageLoopForIO::IOContext* context, |
DWORD bytes_transfered, |
DWORD error) { |
- NOTREACHED(); |
+ if (error != 0) { |
+ if (native_process_handle_ != base::kNullProcessHandle && |
+ base::GetTerminationStatus(native_process_handle_, NULL) != |
+ base::TERMINATION_STATUS_STILL_RUNNING) { |
+ // Notify the message service that the channel should close. |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&Client::CloseChannel, weak_client_ui_, |
+ destination_port_, true)); |
+ } |
+ return; |
+ } |
+ |
+ if (context == read_context_.get()) { |
+ switch (read_state) { |
+ case READ_STATE_INVALID: |
+ // This could be the case on destruction. |
+ return; |
+ case READ_STATE_WAITING_FOR_META: { |
+ AddToOverlappedOffset(&read_context_->overlapped, bytes_transfered); |
+ |
+ MessageType type; |
+ uint32 message_length = 0; |
+ if (!VerifyMessageMetaData(pending_message_meta_data_, &type, |
+ &message_length)) { |
+ return; |
+ } |
+ pending_message_.resize(message_length, '\0'); |
+ // Try to read the full message. |
+ read_state = READ_STATE_WAITING_FOR_MESSAGE; |
+ ::ReadFile(read_file_, &(pending_message_)[0], message_length, NULL, |
+ &read_context_->overlapped); |
+ return; |
+ } |
+ case READ_STATE_WAITING_FOR_MESSAGE: |
+ AddToOverlappedOffset(&read_context_->overlapped, bytes_transfered); |
+ |
+ // Verify that the entire message was read. |
+ if (bytes_transfered != pending_message_.size()) { |
+ LOG(ERROR) << "Could not read entire message."; |
+ return; |
+ } |
+ // Send the current message |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, |
+ destination_port_, pending_message_)); |
+ // Do not try to read another message if this is only a |
+ // sendNativeMessage(). |
+ if (is_send_message_) { |
+ read_state = READ_STATE_INVALID; |
+ } else { |
+ // Start the read for the next message. |
+ read_state = READ_STATE_WAITING_FOR_META; |
+ ::ReadFile(read_file_, &pending_message_meta_data_, 8, NULL, |
+ &read_context_->overlapped); |
+ } |
+ return; |
+ default: |
+ NOTREACHED(); |
+ return; |
+ } |
+ } else { |
+ DCHECK(context == write_context_.get()); |
+ } |
} |
void NativeMessageProcessHost::InitIO() { |
- NOTREACHED(); |
+ read_context_.reset(new MessageLoopForIO::IOContext()); |
+ write_context_.reset(new MessageLoopForIO::IOContext()); |
+ |
+ memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped)); |
+ memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); |
+ |
+ read_context_->handler = this; |
+ write_context_->handler = this; |
+ |
+ MessageLoopForIO::current()->RegisterIOHandler(read_file_, this); |
+ |
+ // Make a request for the type and length of the first message. |
+ read_state = READ_STATE_WAITING_FOR_META; |
+ ::ReadFile(read_file_, &pending_message_meta_data_, 8, NULL, |
+ &read_context_->overlapped); |
+} |
+ |
+void NativeMessageProcessHost::StopIO() { |
+ read_state = READ_STATE_INVALID; |
+ |
+ MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); |
+ |
+ read_context_->handler = NULL; |
+ write_context_->handler = NULL; |
+ |
+ read_context_.reset(); |
+ write_context_.reset(); |
+ |
+ // Because of the asynchronous IO, ::CloseHandle() may return a non-zero |
+ // status. This is expected, but will trigger a CHECK in |
+ // ScopedHandle::Close(). To circumvent this, we will take ownership of the |
+ // raw handle and close it manually. |
+ ::CloseHandle(scoped_read_file_.Take()); |
+ ::CloseHandle(scoped_write_file_.Take()); |
} |
bool NativeMessageProcessHost::WriteData(FileHandle file, |
const char* data, |
size_t bytes_to_write) { |
- NOTREACHED(); |
- return false; |
-} |
+ DWORD bytes_written = 0; |
+ ::SetLastError(0); |
+ BOOL result = ::WriteFile(file, data, bytes_to_write, &bytes_written, |
+ &write_context_->overlapped); |
-bool NativeMessageProcessHost::ReadData(FileHandle file, |
- char* data, |
- size_t bytes_to_read) { |
- NOTREACHED(); |
- return false; |
+ return result || ::GetLastError() == ERROR_IO_PENDING; |
} |
} // namespace extensions |