// Copyright (c) 2010 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 "chrome/common/socket_stream_dispatcher.h" #include #include "base/id_map.h" #include "base/message_loop.h" #include "base/ref_counted.h" #include "base/task.h" #include "chrome/common/child_thread.h" #include "chrome/common/render_messages.h" #include "chrome/common/net/socket_stream.h" #include "googleurl/src/gurl.h" #include "ipc/ipc_message.h" #include "webkit/glue/websocketstreamhandle_bridge.h" #include "webkit/glue/websocketstreamhandle_delegate.h" // 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_(chrome_common_net::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); virtual bool Send(const std::vector& data); virtual void Close(); // Called by SocketStreamDispatcher. void OnConnected(int max_amount_send_allowed); void OnSentData(int amount_sent); void OnReceivedData(const std::vector& data); void OnClosed(); private: virtual ~IPCWebSocketStreamHandleBridge(); void DoConnect(const GURL& url); int socket_id_; ChildThread* child_thread_; WebKit::WebSocketStreamHandle* handle_; webkit_glue::WebSocketStreamHandleDelegate* delegate_; static IDMap all_bridges; }; IDMap IPCWebSocketStreamHandleBridge::all_bridges; /* static */ IPCWebSocketStreamHandleBridge* IPCWebSocketStreamHandleBridge::FromSocketId( int id) { return all_bridges.Lookup(id); } IPCWebSocketStreamHandleBridge::~IPCWebSocketStreamHandleBridge() { DVLOG(1) << "IPCWebSocketStreamHandleBridge destructor socket_id=" << socket_id_; if (socket_id_ != chrome_common_net::kNoSocketId) { child_thread_->Send(new ViewHostMsg_Close(socket_id_)); socket_id_ = chrome_common_net::kNoSocketId; } } void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) { DCHECK(child_thread_); DVLOG(1) << "Connect url=" << url; child_thread_->message_loop()->PostTask( FROM_HERE, NewRunnableMethod(this, &IPCWebSocketStreamHandleBridge::DoConnect, url)); } bool IPCWebSocketStreamHandleBridge::Send( const std::vector& data) { DVLOG(1) << "Send data.size=" << data.size(); if (child_thread_->Send( new ViewHostMsg_SocketStream_SendData(socket_id_, data))) { if (delegate_) delegate_->WillSendData(handle_, &data[0], data.size()); return true; } return false; } void IPCWebSocketStreamHandleBridge::Close() { DVLOG(1) << "Close socket_id" << socket_id_; child_thread_->Send(new ViewHostMsg_SocketStream_Close(socket_id_)); } void IPCWebSocketStreamHandleBridge::OnConnected(int max_pending_send_allowed) { DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnConnected socket_id=" << socket_id_; if (delegate_) delegate_->DidOpenStream(handle_, max_pending_send_allowed); } void IPCWebSocketStreamHandleBridge::OnSentData(int amount_sent) { if (delegate_) delegate_->DidSendData(handle_, amount_sent); } void IPCWebSocketStreamHandleBridge::OnReceivedData( const std::vector& data) { if (delegate_) delegate_->DidReceiveData(handle_, &data[0], data.size()); } void IPCWebSocketStreamHandleBridge::OnClosed() { DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnClosed"; if (socket_id_ != chrome_common_net::kNoSocketId) { all_bridges.Remove(socket_id_); socket_id_ = chrome_common_net::kNoSocketId; } if (delegate_) delegate_->DidClose(handle_); delegate_ = NULL; Release(); } void IPCWebSocketStreamHandleBridge::DoConnect(const GURL& url) { DCHECK(child_thread_); DCHECK_EQ(socket_id_, chrome_common_net::kNoSocketId); if (delegate_) delegate_->WillOpenStream(handle_, url); socket_id_ = all_bridges.Add(this); DCHECK_NE(socket_id_, chrome_common_net::kNoSocketId); if (child_thread_->Send( new ViewHostMsg_SocketStream_Connect(url, socket_id_))) { DVLOG(1) << "Connect socket_id=" << socket_id_; AddRef(); // Released in OnClosed(). // TODO(ukai): timeout to OnConnected. } else { LOG(ERROR) << "IPC SocketStream_Connect failed."; OnClosed(); } } 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(ViewMsg_SocketStream_Connected, OnConnected) IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_SentData, OnSentData) IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_ReceivedData, OnReceivedData) IPC_MESSAGE_HANDLER(ViewMsg_SocketStream_Closed, OnClosed) 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 socket_id=" << socket_id << " max_pending_send_allowed=" << max_pending_send_allowed; IPCWebSocketStreamHandleBridge* bridge = IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); if (bridge) bridge->OnConnected(max_pending_send_allowed); else DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; } void SocketStreamDispatcher::OnSentData(int socket_id, int amount_sent) { IPCWebSocketStreamHandleBridge* bridge = IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); if (bridge) bridge->OnSentData(amount_sent); else DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; } void SocketStreamDispatcher::OnReceivedData( int socket_id, const std::vector& data) { IPCWebSocketStreamHandleBridge* bridge = IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); if (bridge) bridge->OnReceivedData(data); else DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; } void SocketStreamDispatcher::OnClosed(int socket_id) { IPCWebSocketStreamHandleBridge* bridge = IPCWebSocketStreamHandleBridge::FromSocketId(socket_id); if (bridge) bridge->OnClosed(); else DLOG(ERROR) << "No SocketStreamHandleBridge for socket_id=" << socket_id; }