| // 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/renderer/p2p/socket_dispatcher.h" |
| |
| #include "base/bind.h" |
| #include "base/memory/ref_counted.h" |
| #include "content/child/child_process.h" |
| #include "content/common/p2p_messages.h" |
| #include "content/renderer/p2p/host_address_request.h" |
| #include "content/renderer/p2p/network_list_observer.h" |
| #include "content/renderer/p2p/socket_client_impl.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "ipc/ipc_sender.h" |
| |
| namespace content { |
| |
| P2PSocketDispatcher::P2PSocketDispatcher( |
| base::SingleThreadTaskRunner* ipc_task_runner) |
| : ipc_task_runner_(ipc_task_runner), |
| network_notifications_started_(false), |
| network_list_observers_( |
| new base::ObserverListThreadSafe<NetworkListObserver>()), |
| sender_(NULL) { |
| } |
| |
| P2PSocketDispatcher::~P2PSocketDispatcher() { |
| network_list_observers_->AssertEmpty(); |
| for (IDMap<P2PSocketClientImpl>::iterator i(&clients_); !i.IsAtEnd(); |
| i.Advance()) { |
| i.GetCurrentValue()->Detach(); |
| } |
| } |
| |
| void P2PSocketDispatcher::AddNetworkListObserver( |
| NetworkListObserver* network_list_observer) { |
| network_list_observers_->AddObserver(network_list_observer); |
| network_notifications_started_ = true; |
| SendP2PMessage(new P2PHostMsg_StartNetworkNotifications()); |
| } |
| |
| void P2PSocketDispatcher::RemoveNetworkListObserver( |
| NetworkListObserver* network_list_observer) { |
| network_list_observers_->RemoveObserver(network_list_observer); |
| } |
| |
| void P2PSocketDispatcher::Send(IPC::Message* message) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| if (!sender_) { |
| DLOG(WARNING) << "P2PSocketDispatcher::Send() - Sender closed."; |
| delete message; |
| return; |
| } |
| |
| sender_->Send(message); |
| } |
| |
| bool P2PSocketDispatcher::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcher, message) |
| IPC_MESSAGE_HANDLER(P2PMsg_NetworkListChanged, OnNetworkListChanged) |
| IPC_MESSAGE_HANDLER(P2PMsg_GetHostAddressResult, OnGetHostAddressResult) |
| IPC_MESSAGE_HANDLER(P2PMsg_OnSocketCreated, OnSocketCreated) |
| IPC_MESSAGE_HANDLER(P2PMsg_OnIncomingTcpConnection, OnIncomingTcpConnection) |
| IPC_MESSAGE_HANDLER(P2PMsg_OnSendComplete, OnSendComplete) |
| IPC_MESSAGE_HANDLER(P2PMsg_OnError, OnError) |
| IPC_MESSAGE_HANDLER(P2PMsg_OnDataReceived, OnDataReceived) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void P2PSocketDispatcher::OnFilterAdded(IPC::Channel* channel) { |
| DVLOG(1) << "P2PSocketDispatcher::OnFilterAdded()"; |
| sender_ = channel; |
| } |
| |
| void P2PSocketDispatcher::OnFilterRemoved() { |
| sender_ = NULL; |
| } |
| |
| void P2PSocketDispatcher::OnChannelConnected(int32_t peer_id) { |
| connected_ = true; |
| } |
| |
| void P2PSocketDispatcher::OnChannelClosing() { |
| sender_ = NULL; |
| connected_ = false; |
| } |
| |
| base::SingleThreadTaskRunner* P2PSocketDispatcher::task_runner() { |
| return ipc_task_runner_.get(); |
| } |
| |
| int P2PSocketDispatcher::RegisterClient(P2PSocketClientImpl* client) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| return clients_.Add(client); |
| } |
| |
| void P2PSocketDispatcher::UnregisterClient(int id) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| clients_.Remove(id); |
| } |
| |
| void P2PSocketDispatcher::SendP2PMessage(IPC::Message* msg) { |
| if (!ipc_task_runner_->BelongsToCurrentThread()) { |
| ipc_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&P2PSocketDispatcher::Send, this, msg)); |
| return; |
| } |
| Send(msg); |
| } |
| |
| int P2PSocketDispatcher::RegisterHostAddressRequest( |
| P2PAsyncAddressResolver* request) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| return host_address_requests_.Add(request); |
| } |
| |
| void P2PSocketDispatcher::UnregisterHostAddressRequest(int id) { |
| DCHECK(ipc_task_runner_->BelongsToCurrentThread()); |
| host_address_requests_.Remove(id); |
| } |
| |
| void P2PSocketDispatcher::OnNetworkListChanged( |
| const net::NetworkInterfaceList& networks, |
| const net::IPAddress& default_ipv4_local_address, |
| const net::IPAddress& default_ipv6_local_address) { |
| network_list_observers_->Notify( |
| FROM_HERE, &NetworkListObserver::OnNetworkListChanged, networks, |
| default_ipv4_local_address, default_ipv6_local_address); |
| } |
| |
| void P2PSocketDispatcher::OnGetHostAddressResult( |
| int32_t request_id, |
| const net::IPAddressList& addresses) { |
| P2PAsyncAddressResolver* request = host_address_requests_.Lookup(request_id); |
| if (!request) { |
| DVLOG(1) << "Received P2P message for socket that doesn't exist."; |
| return; |
| } |
| |
| request->OnResponse(addresses); |
| } |
| |
| void P2PSocketDispatcher::OnSocketCreated( |
| int socket_id, |
| const net::IPEndPoint& local_address, |
| const net::IPEndPoint& remote_address) { |
| P2PSocketClientImpl* client = GetClient(socket_id); |
| if (client) { |
| client->OnSocketCreated(local_address, remote_address); |
| } |
| } |
| |
| void P2PSocketDispatcher::OnIncomingTcpConnection( |
| int socket_id, const net::IPEndPoint& address) { |
| P2PSocketClientImpl* client = GetClient(socket_id); |
| if (client) { |
| client->OnIncomingTcpConnection(address); |
| } |
| } |
| |
| void P2PSocketDispatcher::OnSendComplete( |
| int socket_id, |
| const P2PSendPacketMetrics& send_metrics) { |
| P2PSocketClientImpl* client = GetClient(socket_id); |
| if (client) { |
| client->OnSendComplete(send_metrics); |
| } |
| } |
| |
| void P2PSocketDispatcher::OnError(int socket_id) { |
| P2PSocketClientImpl* client = GetClient(socket_id); |
| if (client) { |
| client->OnError(); |
| } |
| } |
| |
| void P2PSocketDispatcher::OnDataReceived( |
| int socket_id, const net::IPEndPoint& address, |
| const std::vector<char>& data, |
| const base::TimeTicks& timestamp) { |
| P2PSocketClientImpl* client = GetClient(socket_id); |
| if (client) { |
| client->OnDataReceived(address, data, timestamp); |
| } |
| } |
| |
| P2PSocketClientImpl* P2PSocketDispatcher::GetClient(int socket_id) { |
| P2PSocketClientImpl* client = clients_.Lookup(socket_id); |
| if (client == NULL) { |
| // This may happen if the socket was closed, but the browser side |
| // hasn't processed the close message by the time it sends the |
| // message to the renderer. |
| DVLOG(1) << "Received P2P message for socket that doesn't exist."; |
| return NULL; |
| } |
| |
| return client; |
| } |
| |
| } // namespace content |