// 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 #include "base/bind.h" #include "base/id_map.h" #include "base/lazy_instance.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/strings/string16.h" #include "base/strings/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 "net/base/net_errors.h" #include "url/gurl.h" #include "webkit/child/websocketstreamhandle_bridge.h" #include "webkit/child/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( blink::WebSocketStreamHandle* handle, webkit_glue::WebSocketStreamHandleDelegate* delegate) : socket_id_(kNoSocketId), 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& 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& data); void OnClosed(); void OnFailed(int error_code, const char* error_msg); private: virtual ~IPCWebSocketStreamHandleBridge(); // The ID for this bridge and corresponding SocketStream instance in the // browser process. int socket_id_; blink::WebSocketStreamHandle* handle_; webkit_glue::WebSocketStreamHandleDelegate* delegate_; // Map from ID to bridge instance. static base::LazyInstance >::Leaky all_bridges; }; // static base::LazyInstance >::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; ChildThread::current()->Send(new SocketStreamHostMsg_Close(socket_id_)); socket_id_ = kNoSocketId; } void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) { DVLOG(1) << "Bridge (" << this << ") Connect (url=" << url << ")"; 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(). ChildThread::current()->Send( new SocketStreamHostMsg_Connect(render_view_id, url, socket_id_)); DVLOG(1) << "Bridge #" << socket_id_ << " sent IPC Connect"; // TODO(ukai): timeout to OnConnected. } bool IPCWebSocketStreamHandleBridge::Send(const std::vector& data) { DVLOG(1) << "Bridge #" << socket_id_ << " Send (" << data.size() << " bytes)"; ChildThread::current()->Send( new SocketStreamHostMsg_SendData(socket_id_, data)); if (delegate_) delegate_->WillSendData(handle_, &data[0], data.size()); return true; } void IPCWebSocketStreamHandleBridge::Close() { DVLOG(1) << "Bridge #" << socket_id_ << " Close"; ChildThread::current()->Send(new SocketStreamHostMsg_Close(socket_id_)); } 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& 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)); } SocketStreamDispatcher::SocketStreamDispatcher() { } /* static */ webkit_glue::WebSocketStreamHandleBridge* SocketStreamDispatcher::CreateBridge( blink::WebSocketStreamHandle* handle, webkit_glue::WebSocketStreamHandleDelegate* delegate) { return new IPCWebSocketStreamHandleBridge(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& 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