Chromium Code Reviews| Index: content/browser/renderer_host/pepper_message_filter.cc |
| diff --git a/content/browser/renderer_host/pepper_message_filter.cc b/content/browser/renderer_host/pepper_message_filter.cc |
| index e38e376d1a0f5168f158af5402d3b375b786ca23..4f63142cabd07f57f12b3388746396b4f8b44125 100644 |
| --- a/content/browser/renderer_host/pepper_message_filter.cc |
| +++ b/content/browser/renderer_host/pepper_message_filter.cc |
| @@ -24,13 +24,18 @@ |
| #include "content/browser/resource_context.h" |
| #include "content/common/pepper_messages.h" |
| #include "net/base/address_list.h" |
| +#include "net/base/cert_verifier.h" |
| #include "net/base/ip_endpoint.h" |
| -#include "net/base/net_errors.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/host_resolver.h" |
| #include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| #include "net/base/single_request_host_resolver.h" |
| +#include "net/base/ssl_config_service.h" |
| #include "net/base/sys_addrinfo.h" |
| +#include "net/socket/client_socket_factory.h" |
| +#include "net/socket/client_socket_handle.h" |
| +#include "net/socket/ssl_client_socket.h" |
| #include "net/socket/tcp_client_socket.h" |
| #include "net/url_request/url_request_context.h" |
| #include "ppapi/c/private/ppb_flash_net_connector.h" |
| @@ -120,7 +125,7 @@ const PP_Flash_NetAddress kInvalidNetAddress = { 0 }; |
| class PepperMessageFilter::FlashTCPSocket { |
| public: |
| - FlashTCPSocket(PepperMessageFilter* pepper_message_filter, |
| + FlashTCPSocket(FlashTCPSocketManager* manager, |
| int32 routing_id, |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id); |
| @@ -128,32 +133,53 @@ class PepperMessageFilter::FlashTCPSocket { |
| void Connect(const std::string& host, uint16_t port); |
| void ConnectWithNetAddress(const PP_Flash_NetAddress& net_addr); |
| + void InitiateSSL(const std::string& server_name); |
| void Read(int32 bytes_to_read); |
| void Write(const std::string& data); |
| private: |
| + enum ConnectionState { |
| + // Before a connection is successfully established (including a previous |
| + // connect request failed). |
| + BEFORE_CONNECT, |
| + // There is a connect request that is pending. |
| + CONNECT_IN_PROGRESS, |
| + // A connection has been successfully established. |
| + CONNECTED, |
| + // There is a request of initiating SSL that is pending. |
| + INITIATE_SSL_IN_PROGRESS, |
| + // An SSL connection has been successfully established. |
| + SSL_CONNECTED, |
| + // A request of initiating SSL has failed. |
| + INITIATE_SSL_FAILED |
| + }; |
| + |
| void StartConnect(const net::AddressList& addresses); |
| void SendConnectACKError(); |
| void SendReadACKError(); |
| void SendWriteACKError(); |
| + void SendInitiateSSLACK(bool succeeded); |
| void OnResolveCompleted(int result); |
| void OnConnectCompleted(int result); |
| + void OnInitiateSSLCompleted(int result); |
| void OnReadCompleted(int result); |
| void OnWriteCompleted(int result); |
| - PepperMessageFilter* pepper_message_filter_; |
| + bool IsConnected() const; |
| + |
| + FlashTCPSocketManager* manager_; |
| int32 routing_id_; |
| uint32 plugin_dispatcher_id_; |
| uint32 socket_id_; |
| - bool connect_in_progress_; |
| - bool connected_; |
| + ConnectionState connection_state_; |
| bool end_of_file_reached_; |
| net::CompletionCallbackImpl<FlashTCPSocket> resolve_callback_; |
| net::CompletionCallbackImpl<FlashTCPSocket> connect_callback_; |
| + net::CompletionCallbackImpl<FlashTCPSocket> initiate_ssl_callback_; |
| net::CompletionCallbackImpl<FlashTCPSocket> read_callback_; |
| net::CompletionCallbackImpl<FlashTCPSocket> write_callback_; |
| @@ -168,27 +194,75 @@ class PepperMessageFilter::FlashTCPSocket { |
| DISALLOW_COPY_AND_ASSIGN(FlashTCPSocket); |
| }; |
| +// FlashTCPSocketManager manages the mapping from socket IDs to FlashTCPSocket |
| +// instances. |
| +class PepperMessageFilter::FlashTCPSocketManager { |
| + public: |
| + explicit FlashTCPSocketManager(PepperMessageFilter* pepper_message_filter); |
| + |
| + void OnMsgCreate(int32 routing_id, |
| + uint32 plugin_dispatcher_id, |
| + uint32* socket_id); |
| + void OnMsgConnect(uint32 socket_id, |
| + const std::string& host, |
| + uint16_t port); |
| + void OnMsgConnectWithNetAddress(uint32 socket_id, |
| + const PP_Flash_NetAddress& net_addr); |
| + void OnMsgInitiateSSL(uint32 socket_id, const std::string& server_name); |
| + void OnMsgRead(uint32 socket_id, int32_t bytes_to_read); |
| + void OnMsgWrite(uint32 socket_id, const std::string& data); |
| + void OnMsgDisconnect(uint32 socket_id); |
| + |
| + // Used by FlashTCPSocket. |
| + bool Send(IPC::Message* message) { |
| + return pepper_message_filter_->Send(message); |
| + } |
| + net::HostResolver* GetHostResolver() { |
| + return pepper_message_filter_->GetHostResolver(); |
| + } |
| + const net::SSLConfig& GetSSLConfig(); |
| + const net::SSLClientSocketContext& GetSSLClientSocketContext(); |
|
yzshen1
2011/08/12 21:31:39
wtc: change this method to GetCertVerifier() to cr
yzshen1
2011/08/13 00:40:34
Done.
|
| + |
| + private: |
| + typedef std::map<uint32, linked_ptr<FlashTCPSocket> > SocketMap; |
| + SocketMap sockets_; |
| + |
| + uint32 next_socket_id_; |
| + |
| + PepperMessageFilter* pepper_message_filter_; |
| + |
| + // These are lazily created. Users should use |
| + // GetSSLConfig/GetSSLClientSocketContext to retrieve them. |
| + scoped_ptr<net::SSLConfig> ssl_config_; |
|
yzshen1
2011/08/12 21:31:39
wtc: consider making this a regular member:
net:
yzshen1
2011/08/13 00:40:34
Done.
|
| + scoped_ptr<net::SSLClientSocketContext> ssl_client_socket_context_; |
|
yzshen1
2011/08/12 21:31:39
wtc: Delete this member.
yzshen1
2011/08/13 00:40:34
Done.
|
| + scoped_ptr<net::CertVerifier> cert_verifier_; |
|
wtc
2011/08/09 21:21:29
The net::CertVerifier should be stored in net::SSL
yzshen1
2011/08/09 23:45:29
SSLClientSocketContext doesn't take ownership of i
|
| + |
| + DISALLOW_COPY_AND_ASSIGN(FlashTCPSocketManager); |
| +}; |
| + |
| PepperMessageFilter::FlashTCPSocket::FlashTCPSocket( |
| - PepperMessageFilter* pepper_message_filter, |
| + FlashTCPSocketManager* manager, |
| int32 routing_id, |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id) |
| - : pepper_message_filter_(pepper_message_filter), |
| + : manager_(manager), |
| routing_id_(routing_id), |
| plugin_dispatcher_id_(plugin_dispatcher_id), |
| socket_id_(socket_id), |
| - connect_in_progress_(false), |
| - connected_(false), |
| + connection_state_(BEFORE_CONNECT), |
| end_of_file_reached_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| resolve_callback_(this, &FlashTCPSocket::OnResolveCompleted)), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| connect_callback_(this, &FlashTCPSocket::OnConnectCompleted)), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| + initiate_ssl_callback_(this, |
| + &FlashTCPSocket::OnInitiateSSLCompleted)), |
| + ALLOW_THIS_IN_INITIALIZER_LIST( |
| read_callback_(this, &FlashTCPSocket::OnReadCompleted)), |
| ALLOW_THIS_IN_INITIALIZER_LIST( |
| write_callback_(this, &FlashTCPSocket::OnWriteCompleted)) { |
| - DCHECK(pepper_message_filter); |
| + DCHECK(manager); |
| } |
| PepperMessageFilter::FlashTCPSocket::~FlashTCPSocket() { |
| @@ -201,15 +275,15 @@ void PepperMessageFilter::FlashTCPSocket::Connect(const std::string& host, |
| uint16_t port) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (connect_in_progress_ || connected_) { |
| + if (connection_state_ != BEFORE_CONNECT) { |
| SendConnectACKError(); |
| return; |
| } |
| - connect_in_progress_ = true; |
| + connection_state_ = CONNECT_IN_PROGRESS; |
| net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port)); |
| resolver_.reset(new net::SingleRequestHostResolver( |
| - pepper_message_filter_->GetHostResolver())); |
| + manager_->GetHostResolver())); |
| int result = resolver_->Resolve(request_info, &address_list_, |
| &resolve_callback_, net::BoundNetLog()); |
| if (result != net::ERR_IO_PENDING) |
| @@ -220,20 +294,54 @@ void PepperMessageFilter::FlashTCPSocket::ConnectWithNetAddress( |
| const PP_Flash_NetAddress& net_addr) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (connect_in_progress_ || connected_ || |
| + if (connection_state_ != BEFORE_CONNECT || |
| !NetAddressToAddressList(net_addr, &address_list_)) { |
| SendConnectACKError(); |
| return; |
| } |
| - connect_in_progress_ = true; |
| + connection_state_ = CONNECT_IN_PROGRESS; |
| StartConnect(address_list_); |
| } |
| +void PepperMessageFilter::FlashTCPSocket::InitiateSSL( |
| + const std::string& server_name) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + // Allow to initiate SSL only if currently the socket has been connected and |
| + // there isn't pending read or write. |
| + // IsConnected() includes the state that SSL has been initiated and therefore |
| + // isn't suitable here. |
| + if (connection_state_ != CONNECTED || read_buffer_.get() || |
| + write_buffer_.get()) { |
| + SendInitiateSSLACK(false); |
| + return; |
| + } |
| + |
| + connection_state_ = INITIATE_SSL_IN_PROGRESS; |
| + net::ClientSocketHandle* handle = new net::ClientSocketHandle(); |
| + handle->set_socket(socket_.release()); |
| + net::ClientSocketFactory* factory = |
| + net::ClientSocketFactory::GetDefaultFactory(); |
| + net::HostPortPair host_port_pair; |
| + host_port_pair.set_host(server_name); |
|
wtc
2011/08/09 21:21:29
This means you can only use the default HTTPS port
yzshen1
2011/08/09 23:45:29
The constructors of SSLClientSocket* have the foll
yzshen1
2011/08/13 00:40:34
Done. Thanks for all the explanation.
|
| + socket_.reset(factory->CreateSSLClientSocket( |
| + handle, host_port_pair, manager_->GetSSLConfig(), NULL, |
| + manager_->GetSSLClientSocketContext())); |
|
yzshen1
2011/08/12 21:31:39
wtc:
SSLClientSocketContext ssl_context;
ssl_c
yzshen1
2011/08/13 00:40:34
Done.
|
| + if (!socket_.get()) { |
| + OnInitiateSSLCompleted(net::ERR_UNEXPECTED); |
| + return; |
| + } |
| + |
| + int result = socket_->Connect(&initiate_ssl_callback_); |
| + if (result != net::ERR_IO_PENDING) |
| + OnInitiateSSLCompleted(result); |
| +} |
| + |
| void PepperMessageFilter::FlashTCPSocket::Read(int32 bytes_to_read) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (!connected_ || end_of_file_reached_ || read_buffer_.get() || |
| + if (!IsConnected() || end_of_file_reached_ || read_buffer_.get() || |
| bytes_to_read <= 0) { |
| SendReadACKError(); |
| return; |
| @@ -253,7 +361,7 @@ void PepperMessageFilter::FlashTCPSocket::Read(int32 bytes_to_read) { |
| void PepperMessageFilter::FlashTCPSocket::Write(const std::string& data) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - if (!connected_ || write_buffer_.get() || data.empty()) { |
| + if (!IsConnected() || write_buffer_.get() || data.empty()) { |
| SendWriteACKError(); |
| return; |
| } |
| @@ -273,7 +381,7 @@ void PepperMessageFilter::FlashTCPSocket::Write(const std::string& data) { |
| void PepperMessageFilter::FlashTCPSocket::StartConnect( |
| const net::AddressList& addresses) { |
| - DCHECK(connect_in_progress_); |
| + DCHECK(connection_state_ == CONNECT_IN_PROGRESS); |
| socket_.reset( |
| new net::TCPClientSocket(addresses, NULL, net::NetLog::Source())); |
| @@ -283,31 +391,32 @@ void PepperMessageFilter::FlashTCPSocket::StartConnect( |
| } |
| void PepperMessageFilter::FlashTCPSocket::SendConnectACKError() { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_ConnectACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, false, |
| - kInvalidNetAddress, kInvalidNetAddress)); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ConnectACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, false, |
| + kInvalidNetAddress, kInvalidNetAddress)); |
| } |
| void PepperMessageFilter::FlashTCPSocket::SendReadACKError() { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, false, |
| - std::string())); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, false, std::string())); |
| } |
| void PepperMessageFilter::FlashTCPSocket::SendWriteACKError() { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_WriteACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, false, 0)); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_WriteACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, false, 0)); |
| +} |
| + |
| +void PepperMessageFilter::FlashTCPSocket::SendInitiateSSLACK(bool succeeded) { |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_InitiateSSLACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, succeeded)); |
| } |
| void PepperMessageFilter::FlashTCPSocket::OnResolveCompleted(int result) { |
| - DCHECK(connect_in_progress_); |
| + DCHECK(connection_state_ == CONNECT_IN_PROGRESS); |
| if (result != net::OK) { |
| SendConnectACKError(); |
| - connect_in_progress_ = false; |
| + connection_state_ = BEFORE_CONNECT; |
| return; |
| } |
| @@ -315,10 +424,11 @@ void PepperMessageFilter::FlashTCPSocket::OnResolveCompleted(int result) { |
| } |
| void PepperMessageFilter::FlashTCPSocket::OnConnectCompleted(int result) { |
| - DCHECK(connect_in_progress_ && socket_.get()); |
| + DCHECK(connection_state_ == CONNECT_IN_PROGRESS && socket_.get()); |
| if (result != net::OK) { |
| SendConnectACKError(); |
| + connection_state_ = BEFORE_CONNECT; |
| } else { |
| net::IPEndPoint ip_end_point; |
| net::AddressList address_list; |
| @@ -330,31 +440,35 @@ void PepperMessageFilter::FlashTCPSocket::OnConnectCompleted(int result) { |
| socket_->GetPeerAddress(&address_list) != net::OK || |
| !AddressListToNetAddress(address_list, &remote_addr)) { |
| SendConnectACKError(); |
| + connection_state_ = BEFORE_CONNECT; |
| } else { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_ConnectACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, true, |
| - local_addr, remote_addr)); |
| - connected_ = true; |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ConnectACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, true, |
| + local_addr, remote_addr)); |
| + connection_state_ = CONNECTED; |
| } |
| } |
| - connect_in_progress_ = false; |
| +} |
| + |
| +void PepperMessageFilter::FlashTCPSocket::OnInitiateSSLCompleted(int result) { |
| + DCHECK(connection_state_ == INITIATE_SSL_IN_PROGRESS); |
| + |
| + bool succeeded = result == net::OK; |
| + SendInitiateSSLACK(succeeded); |
| + connection_state_ = succeeded ? SSL_CONNECTED : INITIATE_SSL_FAILED; |
| } |
| void PepperMessageFilter::FlashTCPSocket::OnReadCompleted(int result) { |
| DCHECK(read_buffer_.get()); |
| if (result > 0) { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, true, |
| - std::string(read_buffer_->data(), result))); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, true, |
| + std::string(read_buffer_->data(), result))); |
| } else if (result == 0) { |
| end_of_file_reached_ = true; |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, true, |
| - std::string())); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_ReadACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, true, std::string())); |
| } else { |
| SendReadACKError(); |
| } |
| @@ -365,42 +479,18 @@ void PepperMessageFilter::FlashTCPSocket::OnWriteCompleted(int result) { |
| DCHECK(write_buffer_.get()); |
| if (result >= 0) { |
| - pepper_message_filter_->Send( |
| - new PpapiMsg_PPBFlashTCPSocket_WriteACK( |
| - routing_id_, plugin_dispatcher_id_, socket_id_, true, result)); |
| + manager_->Send(new PpapiMsg_PPBFlashTCPSocket_WriteACK( |
| + routing_id_, plugin_dispatcher_id_, socket_id_, true, result)); |
| } else { |
| SendWriteACKError(); |
| } |
| write_buffer_ = NULL; |
| } |
| -// FlashTCPSocketManager manages the mapping from socket IDs to FlashTCPSocket |
| -// instances. |
| -class PepperMessageFilter::FlashTCPSocketManager { |
| - public: |
| - explicit FlashTCPSocketManager(PepperMessageFilter* pepper_message_filter); |
| - |
| - void OnMsgCreate(int32 routing_id, |
| - uint32 plugin_dispatcher_id, |
| - uint32* socket_id); |
| - void OnMsgConnect(uint32 socket_id, |
| - const std::string& host, |
| - uint16_t port); |
| - void OnMsgConnectWithNetAddress(uint32 socket_id, |
| - const PP_Flash_NetAddress& net_addr); |
| - void OnMsgRead(uint32 socket_id, int32_t bytes_to_read); |
| - void OnMsgWrite(uint32 socket_id, const std::string& data); |
| - void OnMsgDisconnect(uint32 socket_id); |
| - |
| - private: |
| - typedef std::map<uint32, linked_ptr<FlashTCPSocket> > SocketMap; |
| - SocketMap sockets_; |
| - |
| - uint32 next_socket_id_; |
| - |
| - PepperMessageFilter* pepper_message_filter_; |
| - DISALLOW_COPY_AND_ASSIGN(FlashTCPSocketManager); |
| -}; |
| +bool PepperMessageFilter::FlashTCPSocket::IsConnected() const { |
| + return connection_state_ == CONNECTED || |
| + connection_state_ == SSL_CONNECTED; |
| +} |
| PepperMessageFilter::FlashTCPSocketManager::FlashTCPSocketManager( |
| PepperMessageFilter* pepper_message_filter) |
| @@ -434,8 +524,7 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgCreate( |
| } while (*socket_id == 0 || |
| sockets_.find(*socket_id) != sockets_.end()); |
| sockets_[*socket_id] = linked_ptr<FlashTCPSocket>( |
| - new FlashTCPSocket(pepper_message_filter_, routing_id, |
| - plugin_dispatcher_id, *socket_id)); |
| + new FlashTCPSocket(this, routing_id, plugin_dispatcher_id, *socket_id)); |
| } |
| void PepperMessageFilter::FlashTCPSocketManager::OnMsgConnect( |
| @@ -463,6 +552,18 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgConnectWithNetAddress( |
| iter->second->ConnectWithNetAddress(net_addr); |
| } |
| +void PepperMessageFilter::FlashTCPSocketManager::OnMsgInitiateSSL( |
| + uint32 socket_id, |
| + const std::string& server_name) { |
| + SocketMap::iterator iter = sockets_.find(socket_id); |
| + if (iter == sockets_.end()) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + iter->second->InitiateSSL(server_name); |
| +} |
| + |
| void PepperMessageFilter::FlashTCPSocketManager::OnMsgRead( |
| uint32 socket_id, |
| int32_t bytes_to_read) { |
| @@ -501,6 +602,25 @@ void PepperMessageFilter::FlashTCPSocketManager::OnMsgDisconnect( |
| sockets_.erase(iter); |
| } |
| +const net::SSLConfig& |
| +PepperMessageFilter::FlashTCPSocketManager::GetSSLConfig() { |
| + if (!ssl_config_.get()) |
| + ssl_config_.reset(new net::SSLConfig()); |
|
wtc
2011/08/09 21:21:29
Ideally you should pass the SSLConfig in the messa
yzshen1
2011/08/09 23:45:29
Currently we only support a minimal set of operati
|
| + |
| + return *ssl_config_; |
| +} |
| + |
| +const net::SSLClientSocketContext& |
| +PepperMessageFilter::FlashTCPSocketManager::GetSSLClientSocketContext() { |
| + if (!ssl_client_socket_context_.get()) { |
| + cert_verifier_.reset(new net::CertVerifier()); |
| + ssl_client_socket_context_.reset(new net::SSLClientSocketContext( |
| + cert_verifier_.get(), NULL, NULL, NULL, NULL)); |
| + } |
| + |
| + return *ssl_client_socket_context_; |
| +} |
| + |
| PepperMessageFilter::PepperMessageFilter( |
| const content::ResourceContext* resource_context) |
| : resource_context_(resource_context), |
| @@ -543,6 +663,10 @@ bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg, |
| socket_manager_.get(), |
| FlashTCPSocketManager::OnMsgConnectWithNetAddress) |
| IPC_MESSAGE_FORWARD( |
| + PpapiHostMsg_PPBFlashTCPSocket_InitiateSSL, |
| + socket_manager_.get(), |
| + FlashTCPSocketManager::OnMsgInitiateSSL) |
| + IPC_MESSAGE_FORWARD( |
| PpapiHostMsg_PPBFlashTCPSocket_Read, |
| socket_manager_.get(), FlashTCPSocketManager::OnMsgRead) |
| IPC_MESSAGE_FORWARD( |