diff options
Diffstat (limited to 'content/child/socket_stream_dispatcher.cc')
-rw-r--r-- | content/child/socket_stream_dispatcher.cc | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/content/child/socket_stream_dispatcher.cc b/content/child/socket_stream_dispatcher.cc new file mode 100644 index 0000000..912360c --- /dev/null +++ b/content/child/socket_stream_dispatcher.cc @@ -0,0 +1,286 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/socket_stream_dispatcher.h" + +#include <vector> + +#include "base/bind.h" +#include "base/id_map.h" +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop.h" +#include "base/string16.h" +#include "base/utf_string_conversions.h" +#include "content/child/child_thread.h" +#include "content/common/socket_stream.h" +#include "content/common/socket_stream_handle_data.h" +#include "content/common/socket_stream_messages.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "webkit/glue/websocketstreamhandle_bridge.h" +#include "webkit/glue/websocketstreamhandle_delegate.h" + +namespace content { + +// IPCWebSocketStreamHandleBridge is owned by each SocketStreamHandle. +// It communicates with the main browser process via SocketStreamDispatcher. +class IPCWebSocketStreamHandleBridge + : public webkit_glue::WebSocketStreamHandleBridge { + public: + IPCWebSocketStreamHandleBridge( + ChildThread* child_thread, + WebKit::WebSocketStreamHandle* handle, + webkit_glue::WebSocketStreamHandleDelegate* delegate) + : socket_id_(kNoSocketId), + child_thread_(child_thread), + handle_(handle), + delegate_(delegate) {} + + // Returns the handle having given id or NULL if there is no such handle. + static IPCWebSocketStreamHandleBridge* FromSocketId(int id); + + // webkit_glue::WebSocketStreamHandleBridge methods. + virtual void Connect(const GURL& url) OVERRIDE; + virtual bool Send(const std::vector<char>& data) OVERRIDE; + virtual void Close() OVERRIDE; + + // Called by SocketStreamDispatcher. + void OnConnected(int max_amount_send_allowed); + void OnSentData(int amount_sent); + void OnReceivedData(const std::vector<char>& data); + void OnClosed(); + void OnFailed(int error_code, const char* error_msg); + + private: + virtual ~IPCWebSocketStreamHandleBridge(); + + void DoConnect(const GURL& url); + void DoClose(); + + // The ID for this bridge and corresponding SocketStream instance in the + // browser process. + int socket_id_; + + ChildThread* child_thread_; + WebKit::WebSocketStreamHandle* handle_; + webkit_glue::WebSocketStreamHandleDelegate* delegate_; + + // Map from ID to bridge instance. + static base::LazyInstance<IDMap<IPCWebSocketStreamHandleBridge> >::Leaky + all_bridges; +}; + +// static +base::LazyInstance<IDMap<IPCWebSocketStreamHandleBridge> >::Leaky + IPCWebSocketStreamHandleBridge::all_bridges = LAZY_INSTANCE_INITIALIZER; + +/* static */ +IPCWebSocketStreamHandleBridge* IPCWebSocketStreamHandleBridge::FromSocketId( + int id) { + return all_bridges.Get().Lookup(id); +} + +IPCWebSocketStreamHandleBridge::~IPCWebSocketStreamHandleBridge() { + DVLOG(1) << "Bridge (" << this << ", socket_id_=" << socket_id_ + << ") Destructor"; + + if (socket_id_ == kNoSocketId) + return; + + child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_)); + socket_id_ = kNoSocketId; +} + +void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) { + DCHECK(child_thread_); + DVLOG(1) << "Bridge (" << this << ") Connect (url=" << url << ")"; + + child_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&IPCWebSocketStreamHandleBridge::DoConnect, this, url)); +} + +bool IPCWebSocketStreamHandleBridge::Send( + const std::vector<char>& data) { + DVLOG(1) << "Bridge #" << socket_id_ << " Send (" << data.size() + << " bytes)"; + + if (child_thread_->Send( + new SocketStreamHostMsg_SendData(socket_id_, data))) { + if (delegate_) + delegate_->WillSendData(handle_, &data[0], data.size()); + return true; + } + return false; +} + +void IPCWebSocketStreamHandleBridge::Close() { + DVLOG(1) << "Bridge #" << socket_id_ << " Close"; + + AddRef(); // Released in DoClose(). + child_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&IPCWebSocketStreamHandleBridge::DoClose, this)); +} + +void IPCWebSocketStreamHandleBridge::OnConnected(int max_pending_send_allowed) { + DVLOG(1) << "Bridge #" << socket_id_ + << " OnConnected (max_pending_send_allowed=" + << max_pending_send_allowed << ")"; + + if (delegate_) + delegate_->DidOpenStream(handle_, max_pending_send_allowed); +} + +void IPCWebSocketStreamHandleBridge::OnSentData(int amount_sent) { + DVLOG(1) << "Bridge #" << socket_id_ << " OnSentData (" << amount_sent + << " bytes)"; + + if (delegate_) + delegate_->DidSendData(handle_, amount_sent); +} + +void IPCWebSocketStreamHandleBridge::OnReceivedData( + const std::vector<char>& data) { + DVLOG(1) << "Bridge #" << socket_id_ << " OnReceiveData (" << data.size() + << " bytes)"; + if (delegate_) + delegate_->DidReceiveData(handle_, &data[0], data.size()); +} + +void IPCWebSocketStreamHandleBridge::OnClosed() { + DVLOG(1) << "Bridge #" << socket_id_ << " OnClosed"; + + if (socket_id_ != kNoSocketId) { + all_bridges.Get().Remove(socket_id_); + socket_id_ = kNoSocketId; + } + if (delegate_) + delegate_->DidClose(handle_); + delegate_ = NULL; + Release(); +} + +void IPCWebSocketStreamHandleBridge::OnFailed(int error_code, + const char* error_msg) { + DVLOG(1) << "Bridge #" << socket_id_ << " OnFailed (error_code=" << error_code + << ")"; + if (delegate_) + delegate_->DidFail(handle_, error_code, ASCIIToUTF16(error_msg)); +} + +void IPCWebSocketStreamHandleBridge::DoConnect(const GURL& url) { + DCHECK(child_thread_); + DCHECK_EQ(socket_id_, kNoSocketId); + if (delegate_) + delegate_->WillOpenStream(handle_, url); + + socket_id_ = all_bridges.Get().Add(this); + DCHECK_NE(socket_id_, kNoSocketId); + int render_view_id = MSG_ROUTING_NONE; + const SocketStreamHandleData* data = + SocketStreamHandleData::ForHandle(handle_); + if (data) + render_view_id = data->render_view_id(); + AddRef(); // Released in OnClosed(). + if (child_thread_->Send( + new SocketStreamHostMsg_Connect(render_view_id, url, socket_id_))) { + DVLOG(1) << "Bridge #" << socket_id_ << " sent IPC Connect"; + // TODO(ukai): timeout to OnConnected. + } else { + DLOG(ERROR) << "Bridge #" << socket_id_ << " failed to send IPC Connect"; + OnClosed(); + } +} + +void IPCWebSocketStreamHandleBridge::DoClose() { + child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_)); + Release(); +} + +SocketStreamDispatcher::SocketStreamDispatcher() { +} + +/* static */ +webkit_glue::WebSocketStreamHandleBridge* +SocketStreamDispatcher::CreateBridge( + WebKit::WebSocketStreamHandle* handle, + webkit_glue::WebSocketStreamHandleDelegate* delegate) { + return new IPCWebSocketStreamHandleBridge( + ChildThread::current(), handle, delegate); +} + +bool SocketStreamDispatcher::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(SocketStreamDispatcher, msg) + IPC_MESSAGE_HANDLER(SocketStreamMsg_Connected, OnConnected) + IPC_MESSAGE_HANDLER(SocketStreamMsg_SentData, OnSentData) + IPC_MESSAGE_HANDLER(SocketStreamMsg_ReceivedData, OnReceivedData) + IPC_MESSAGE_HANDLER(SocketStreamMsg_Closed, OnClosed) + IPC_MESSAGE_HANDLER(SocketStreamMsg_Failed, OnFailed) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void SocketStreamDispatcher::OnConnected(int socket_id, + int max_pending_send_allowed) { + DVLOG(1) << "SocketStreamDispatcher::OnConnected (max_pending_send_allowed=" + << max_pending_send_allowed << ") to socket_id=" << socket_id; + + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnConnected(max_pending_send_allowed); + else + DLOG(ERROR) << "No bridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnSentData(int socket_id, int amount_sent) { + DVLOG(1) << "SocketStreamDispatcher::OnSentData (" << amount_sent + << " bytes) to socket_id=" << socket_id; + + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnSentData(amount_sent); + else + DLOG(ERROR) << "No bridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnReceivedData( + int socket_id, const std::vector<char>& data) { + DVLOG(1) << "SocketStreamDispatcher::OnReceivedData (" << data.size() + << " bytes) to socket_id=" << socket_id; + + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnReceivedData(data); + else + DLOG(ERROR) << "No bridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnClosed(int socket_id) { + DVLOG(1) << "SocketStreamDispatcher::OnClosed to socket_id=" << socket_id; + + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnClosed(); + else + DLOG(ERROR) << "No bridge for socket_id=" << socket_id; +} + +void SocketStreamDispatcher::OnFailed(int socket_id, int error_code) { + IPCWebSocketStreamHandleBridge* bridge = + IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); + if (bridge) + bridge->OnFailed(error_code, net::ErrorToString(error_code)); + else + DLOG(ERROR) << "No bridge for socket_id=" << socket_id; +} + +} // namespace content |