1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
6
7#include "base/bind.h"
8#include "base/stl_util.h"
9#include "content/browser/renderer_host/p2p/socket_host.h"
10#include "content/common/p2p_messages.h"
11#include "content/public/browser/resource_context.h"
12#include "net/base/address_list.h"
13#include "net/base/completion_callback.h"
14#include "net/base/net_errors.h"
15#include "net/base/net_log.h"
16#include "net/base/sys_addrinfo.h"
17#include "net/dns/single_request_host_resolver.h"
18#include "net/url_request/url_request_context_getter.h"
19
20using content::BrowserMessageFilter;
21using content::BrowserThread;
22
23namespace content {
24
25const size_t kMaximumPacketSize = 32768;
26
27class P2PSocketDispatcherHost::DnsRequest {
28 public:
29  typedef base::Callback<void(const net::IPAddressList&)> DoneCallback;
30
31  DnsRequest(int32 request_id, net::HostResolver* host_resolver)
32      : request_id_(request_id),
33        resolver_(host_resolver) {
34  }
35
36  void Resolve(const std::string& host_name,
37               const DoneCallback& done_callback) {
38    DCHECK(!done_callback.is_null());
39
40    host_name_ = host_name;
41    done_callback_ = done_callback;
42
43    // Return an error if it's an empty string.
44    if (host_name_.empty()) {
45      net::IPAddressList address_list;
46      done_callback_.Run(address_list);
47      return;
48    }
49
50    // Add period at the end to make sure that we only resolve
51    // fully-qualified names.
52    if (host_name_.at(host_name_.size() - 1) != '.')
53      host_name_ = host_name_ + '.';
54
55    net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
56    int result = resolver_.Resolve(
57        info,
58        net::DEFAULT_PRIORITY,
59        &addresses_,
60        base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
61                   base::Unretained(this)),
62        net::BoundNetLog());
63    if (result != net::ERR_IO_PENDING)
64      OnDone(result);
65  }
66
67  int32 request_id() { return request_id_; }
68
69 private:
70  void OnDone(int result) {
71    net::IPAddressList list;
72    if (result != net::OK) {
73      LOG(ERROR) << "Failed to resolve address for " << host_name_
74                 << ", errorcode: " << result;
75      done_callback_.Run(list);
76      return;
77    }
78
79    DCHECK(!addresses_.empty());
80    for (net::AddressList::iterator iter = addresses_.begin();
81         iter != addresses_.end(); ++iter) {
82      list.push_back(iter->address());
83    }
84    done_callback_.Run(list);
85  }
86
87  int32 request_id_;
88  net::AddressList addresses_;
89
90  std::string host_name_;
91  net::SingleRequestHostResolver resolver_;
92
93  DoneCallback done_callback_;
94};
95
96P2PSocketDispatcherHost::P2PSocketDispatcherHost(
97    content::ResourceContext* resource_context,
98    net::URLRequestContextGetter* url_context)
99    : BrowserMessageFilter(P2PMsgStart),
100      resource_context_(resource_context),
101      url_context_(url_context),
102      monitoring_networks_(false),
103      dump_incoming_rtp_packet_(false),
104      dump_outgoing_rtp_packet_(false) {
105}
106
107void P2PSocketDispatcherHost::OnChannelClosing() {
108  // Since the IPC sender is gone, close pending connections.
109  STLDeleteContainerPairSecondPointers(sockets_.begin(), sockets_.end());
110  sockets_.clear();
111
112  STLDeleteContainerPointers(dns_requests_.begin(), dns_requests_.end());
113  dns_requests_.clear();
114
115  if (monitoring_networks_) {
116    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
117    monitoring_networks_ = false;
118  }
119}
120
121void P2PSocketDispatcherHost::OnDestruct() const {
122  BrowserThread::DeleteOnIOThread::Destruct(this);
123}
124
125bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
126  bool handled = true;
127  IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcherHost, message)
128    IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications,
129                        OnStartNetworkNotifications)
130    IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications,
131                        OnStopNetworkNotifications)
132    IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress, OnGetHostAddress)
133    IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket, OnCreateSocket)
134    IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection,
135                        OnAcceptIncomingTcpConnection)
136    IPC_MESSAGE_HANDLER(P2PHostMsg_Send, OnSend)
137    IPC_MESSAGE_HANDLER(P2PHostMsg_SetOption, OnSetOption)
138    IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket, OnDestroySocket)
139    IPC_MESSAGE_UNHANDLED(handled = false)
140  IPC_END_MESSAGE_MAP()
141  return handled;
142}
143
144void P2PSocketDispatcherHost::OnIPAddressChanged() {
145  // Notify the renderer about changes to list of network interfaces.
146  BrowserThread::PostTask(
147      BrowserThread::FILE, FROM_HERE, base::Bind(
148          &P2PSocketDispatcherHost::DoGetNetworkList, this));
149}
150
151void P2PSocketDispatcherHost::StartRtpDump(
152    bool incoming,
153    bool outgoing,
154    const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
155  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
156
157  if ((!dump_incoming_rtp_packet_ && incoming) ||
158      (!dump_outgoing_rtp_packet_ && outgoing)) {
159    if (incoming)
160      dump_incoming_rtp_packet_ = true;
161
162    if (outgoing)
163      dump_outgoing_rtp_packet_ = true;
164
165    packet_callback_ = packet_callback;
166    for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
167      it->second->StartRtpDump(incoming, outgoing, packet_callback);
168  }
169}
170
171void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming,
172                                                    bool outgoing) {
173  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174  BrowserThread::PostTask(
175      BrowserThread::IO,
176      FROM_HERE,
177      base::Bind(&P2PSocketDispatcherHost::StopRtpDumpOnIOThread,
178                 this,
179                 incoming,
180                 outgoing));
181}
182
183P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
184  DCHECK(sockets_.empty());
185  DCHECK(dns_requests_.empty());
186
187  if (monitoring_networks_)
188    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
189}
190
191P2PSocketHost* P2PSocketDispatcherHost::LookupSocket(int socket_id) {
192  SocketsMap::iterator it = sockets_.find(socket_id);
193  return (it == sockets_.end()) ? NULL : it->second;
194}
195
196void P2PSocketDispatcherHost::OnStartNetworkNotifications() {
197  if (!monitoring_networks_) {
198    net::NetworkChangeNotifier::AddIPAddressObserver(this);
199    monitoring_networks_ = true;
200  }
201
202  BrowserThread::PostTask(
203      BrowserThread::FILE, FROM_HERE, base::Bind(
204          &P2PSocketDispatcherHost::DoGetNetworkList, this));
205}
206
207void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
208  if (monitoring_networks_) {
209    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
210    monitoring_networks_ = false;
211  }
212}
213
214void P2PSocketDispatcherHost::OnGetHostAddress(const std::string& host_name,
215                                               int32 request_id) {
216  DnsRequest* request = new DnsRequest(request_id,
217                                       resource_context_->GetHostResolver());
218  dns_requests_.insert(request);
219  request->Resolve(host_name, base::Bind(
220      &P2PSocketDispatcherHost::OnAddressResolved,
221      base::Unretained(this), request));
222}
223
224void P2PSocketDispatcherHost::OnCreateSocket(
225    P2PSocketType type, int socket_id,
226    const net::IPEndPoint& local_address,
227    const P2PHostAndIPEndPoint& remote_address) {
228  if (LookupSocket(socket_id)) {
229    LOG(ERROR) << "Received P2PHostMsg_CreateSocket for socket "
230        "that already exists.";
231    return;
232  }
233
234  scoped_ptr<P2PSocketHost> socket(P2PSocketHost::Create(
235      this, socket_id, type, url_context_.get(), &throttler_));
236
237  if (!socket) {
238    Send(new P2PMsg_OnError(socket_id));
239    return;
240  }
241
242  if (socket->Init(local_address, remote_address)) {
243    sockets_[socket_id] = socket.release();
244
245    if (dump_incoming_rtp_packet_ || dump_outgoing_rtp_packet_) {
246      sockets_[socket_id]->StartRtpDump(dump_incoming_rtp_packet_,
247                                        dump_outgoing_rtp_packet_,
248                                        packet_callback_);
249    }
250  }
251}
252
253void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
254    int listen_socket_id, const net::IPEndPoint& remote_address,
255    int connected_socket_id) {
256  P2PSocketHost* socket = LookupSocket(listen_socket_id);
257  if (!socket) {
258    LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
259        "for invalid socket_id.";
260    return;
261  }
262  P2PSocketHost* accepted_connection =
263      socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id);
264  if (accepted_connection) {
265    sockets_[connected_socket_id] = accepted_connection;
266  }
267}
268
269void P2PSocketDispatcherHost::OnSend(int socket_id,
270                                     const net::IPEndPoint& socket_address,
271                                     const std::vector<char>& data,
272                                     const rtc::PacketOptions& options,
273                                     uint64 packet_id) {
274  P2PSocketHost* socket = LookupSocket(socket_id);
275  if (!socket) {
276    LOG(ERROR) << "Received P2PHostMsg_Send for invalid socket_id.";
277    return;
278  }
279
280  if (data.size() > kMaximumPacketSize) {
281    LOG(ERROR) << "Received P2PHostMsg_Send with a packet that is too big: "
282               << data.size();
283    Send(new P2PMsg_OnError(socket_id));
284    delete socket;
285    sockets_.erase(socket_id);
286    return;
287  }
288
289  socket->Send(socket_address, data, options, packet_id);
290}
291
292void P2PSocketDispatcherHost::OnSetOption(int socket_id,
293                                          P2PSocketOption option,
294                                          int value) {
295  P2PSocketHost* socket = LookupSocket(socket_id);
296  if (!socket) {
297    LOG(ERROR) << "Received P2PHostMsg_SetOption for invalid socket_id.";
298    return;
299  }
300
301  socket->SetOption(option, value);
302}
303
304void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
305  SocketsMap::iterator it = sockets_.find(socket_id);
306  if (it != sockets_.end()) {
307    delete it->second;
308    sockets_.erase(it);
309  } else {
310    LOG(ERROR) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
311  }
312}
313
314void P2PSocketDispatcherHost::DoGetNetworkList() {
315  net::NetworkInterfaceList list;
316  net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES |
317                             net::INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE);
318  BrowserThread::PostTask(
319      BrowserThread::IO, FROM_HERE, base::Bind(
320          &P2PSocketDispatcherHost::SendNetworkList, this, list));
321}
322
323void P2PSocketDispatcherHost::SendNetworkList(
324    const net::NetworkInterfaceList& list) {
325  Send(new P2PMsg_NetworkListChanged(list));
326}
327
328void P2PSocketDispatcherHost::OnAddressResolved(
329    DnsRequest* request,
330    const net::IPAddressList& addresses) {
331  Send(new P2PMsg_GetHostAddressResult(request->request_id(), addresses));
332
333  dns_requests_.erase(request);
334  delete request;
335}
336
337void P2PSocketDispatcherHost::StopRtpDumpOnIOThread(bool incoming,
338                                                    bool outgoing) {
339  if ((dump_incoming_rtp_packet_ && incoming) ||
340      (dump_outgoing_rtp_packet_ && outgoing)) {
341    if (incoming)
342      dump_incoming_rtp_packet_ = false;
343
344    if (outgoing)
345      dump_outgoing_rtp_packet_ = false;
346
347    if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
348      packet_callback_.Reset();
349
350    for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
351      it->second->StopRtpDump(incoming, outgoing);
352  }
353}
354
355}  // namespace content
356